nodesty-api-client 1.1.2
nodesty.com için Python API istemci kütüphanesi
Requires Python: >=3.9

# Nodesty Python API Client

[![API](https://img.shields.io/badge/Nodesty-API-green.svg)](https://nodesty.com)
[![Python](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://python.org)
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI](https://img.shields.io/pypi/v/nodesty-api-client.svg)](https://pypi.org/project/nodesty-api-library/1.0.0/)
[![Author](https://img.shields.io/badge/Author--RED.svg)](https://github.com/staticius)

nodesty.com'un güçlü API'sine Python uygulamalarınızdan kolayca erişmenizi sağlayan modern, asenkron ve tip güvenli bir
istemci kütüphanesi. httpx ve pydantic kütüphanelerinin gücünü kullanarak API etkileşimlerinizi basitleştirir.

## 🚀 Özellikler

- **⚡ Asenkron Operasyonlar**: `httpx` ile tam async destek
- **🔒 Tip Güvenliği**: `pydantic` ile güçlü veri modelleri ve doğrulama
- **🔄 Otomatik Serileştirme**: JSON ↔ Python veri tipleri dönüşümü
- **⚙️ Yapılandırılabilir**: Timeout, retry, rate limit ayarları
- **🛡️ Kapsamlı Hata Yönetimi**: Standart `ApiResponse<T>` yapısı
- **📦 Modüler Yapı**: Her servis kendi modülü içinde

## 📋 Desteklenen Servisler

| Servis                | Açıklama                                                  | Erişim                    |
|-----------------------|-----------------------------------------------------------|---------------------------|
| **User Service**      | Kullanıcı profili, hizmetler, faturalar, destek biletleri | `client.user`             |
| **VPS Service**       | VPS yönetimi, yedekler, şifre değişimi, istatistikler     | `client.vps`              |
| **Dedicated Service** | Dedicated sunucu yönetimi, donanım bilgileri              | `client.dedicated_server` |
| **Firewall Service**  | nShield kuralları, saldırı logları, rDNS yönetimi         | `client.firewall`         |

## 🛠️ Kurulum

PyPI üzerinden pip ile kolayca kurabilirsiniz:

```bash
pip install nodesty-api-client
```

## 🔑 Başlangıç

### API Token Alma

1. [Nodesty kontrol paneli](https://nodesty.com/dashboard/my-account/access-tokens) adresine giriş yapın.

### Temel Kullanım

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from datetime import timedelta


async def main():
    token = os.environ.get("NODESTY_API_TOKEN")
    if not token:
        raise ValueError("NODESTY_API_TOKEN ortam değişkeni ayarlanmamış.")

    options = RestClientOptions(access_token=token)
        .with_timeout(timedelta(seconds=45))
        .with_retry(5)
        .with_rate_limit_offset(timedelta(milliseconds=100))

    # Asenkron bağlam yöneticisi olarak NodestyApiClient'i kullanın
    async with NodestyApiClient(options) as client:
        user_response = await client.user.get_current_user()

        if user_response.success:
            if user_response.data:
                print(f"Hoş geldin {user_response.data.name}")
            else:
                print("Kullanıcı bilgisi bulunamadı.")
        else:
            print(f"Kullanıcı bilgisi getirilirken hata oluştu: {user_response.error}")


if __name__ == "__main__":
    asyncio.run(main())
```

## 📖 Kullanım Örnekleri

### 👤 Kullanıcı Bilgileri

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions


async def get_user_info():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)

    async with NodestyApiClient(options) as client:
        res = await client.user.get_current_user()
        if res.success and res.data:
            user = res.data
            print(f"Merhaba {user.full_name}")
            print(f"Email: {user.email}")
        else:
            print(f"Hata: {res.error}")


if __name__ == "__main__":
    asyncio.run(get_user_info())
```

### 🖥️ VPS Yönetimi

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from nodesty_api_client.models.vps import VpsAction


async def manage_vps():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)

    async with NodestyApiClient(options) as client:
        vps_id = "your-vps-id"

        # VPS'i yeniden başlat
        restart_res = await client.vps.perform_action(vps_id, VpsAction.RESTART)
        if restart_res.success:
            print(f"VPS {vps_id} başarıyla yeniden başlatıldı.")
        else:
            print(f"VPS yeniden başlatılırken hata oluştu: {restart_res.error}")

        # Yedekleri listele
        backups_res = await client.vps.get_backups(vps_id)
        if backups_res.success and backups_res.data:
            print("Yedekler:")
            for backup in backups_res.data:
                print(f"- Tarih: {backup.date}, Dosya: {backup.file}")
        else:
            print(f"Yedekler getirilirken hata oluştu: {backups_res.error}")


if __name__ == "__main__":
    asyncio.run(manage_vps())
```

### 🔧 Dedicated Sunucu

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions


async def get_dedicated_info():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)

    async with NodestyApiClient(options) as client:
        dedicated_id = "your-dedicated-id"
        res = await client.dedicated_server.get_hardware_components(dedicated_id)

        if res.success and res.data:
            print("Donanım Bileşenleri:")
            for part in res.data:
                print(f"- {part.component}: {part.model} {part.value}{part.value_suffix}")
        else:
            print(f"Donanım bileşenleri getirilirken hata oluştu: {res.error}")


if __name__ == "__main__":
    asyncio.run(get_dedicated_info())
```

### 🛡️ Güvenlik Duvarı

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions
from nodesty_api_client.models.firewall import FirewallCreateRuleData


async def manage_firewall():
    token = os.environ.get("NODESTY_API_TOKEN")
    options = RestClientOptions(access_token=token)

    async with NodestyApiClient(options) as client:
        service_id = "your-service-id"
        ip_address = "your-ip-address"

        # Yeni bir kural oluştur
        rule_data = FirewallCreateRuleData(port=25565, app_id=123)
        create_res = await client.firewall.create_rule(service_id, ip_address, rule_data)

        if create_res.success:
            print("Güvenlik duvarı kuralı başarıyla oluşturuldu.")
        else:
            print(f"Kural oluşturulurken hata oluştu: {create_res.error}")

        # Saldırı kayıtlarını getir
        logs_res = await client.firewall.get_attack_logs(service_id, ip_address)
        if logs_res.success and logs_res.data:
            print("Saldırı Kayıtları:")
            for log in logs_res.data:
                print(f"- Başlangıç: {log.started_at}, Vektörler: {log.vectors}")
        else:
            print(f"Saldırı kayıtları getirilirken hata oluştu: {logs_res.error}")


if __name__ == "__main__":
    asyncio.run(manage_firewall())
```

## 🏗️ API Yanıt Yapısı

Tüm API çağrıları `ApiResponse<T>` döner:

```python
from typing import TypeVar, Generic, Optional
from pydantic import BaseModel

T = TypeVar('T')


class ApiResponse(BaseModel, Generic[T]):
    success: bool
    error: Optional[str] = None
    data: Optional[T] = None
```

## ⚙️ Yapılandırma Seçenekleri

```python
from nodesty_api_client import RestClientOptions
from datetime import timedelta

options = RestClientOptions(access_token="YOUR_API_TOKEN")
    .with_timeout(timedelta(seconds=30))
    .with_retry(3)
    .with_rate_limit_offset(timedelta(milliseconds=50))
```

## 📚 API Servisleri

### 👤 User Service (`client.user`)

| Metod                   | Açıklama                   | Endpoint                       |
|-------------------------|----------------------------|--------------------------------|
| `get_current_user()`    | Kullanıcı profilini al     | `GET /users/@me`               |
| `get_services()`        | Hizmetleri listele         | `GET /services`                |
| `get_tickets()`         | Destek biletlerini listele | `GET /tickets`                 |
| `get_ticket_by_id(id)`  | Belirli bileti getir       | `GET /tickets/{id}`            |
| `get_invoices()`        | Faturaları listele         | `GET /users/@me/invoices`      |
| `get_invoice_by_id(id)` | Belirli faturayı getir     | `GET /users/@me/invoices/{id}` |
| `get_sessions()`        | Aktif oturumları getir     | `GET /users/@me/sessions`      |

### 🖥️ VPS Service (`client.vps`)

| Metod                        | Açıklama                | Endpoint                                  |
|------------------------------|-------------------------|-------------------------------------------|
| `perform_action(id, action)` | VPS eylemi gerçekleştir | `POST /services/{id}/vps/action`          |
| `get_backups(id)`            | Yedekleri getir         | `GET /services/{id}/vps/backups`          |
| `restore_backup(id, data)`   | Geri yükleme yap        | `POST /services/{id}/vps/backup/restore`  |
| `change_password(id, data)`  | Şifre değiştir          | `POST /services/{id}/vps/change-password` |
| `get_graphs(id)`             | İstatistikleri al       | `GET /services/{id}/vps/graphs`           |
| `get_details(id)`            | VPS detayları           | `GET /services/{id}/vps/info`             |
| `get_os_templates(id)`       | OS şablonlarını getir   | `GET /services/{id}/vps/os-templates`     |
| `reinstall(id, data)`        | Yeniden kurulum         | `POST /services/{id}/vps/reinstall`       |
| `get_tasks(id)`              | Görevleri getir         | `GET /services/{id}/vps/tasks`            |

### 🔧 Dedicated Service (`client.dedicated_server`)

| Metod                         | Açıklama          | Endpoint                                        |
|-------------------------------|-------------------|-------------------------------------------------|
| `perform_action(id, action)`  | Eylem çalıştır    | `POST /services/{id}/dedicated/action`          |
| `get_hardware_components(id)` | Donanım detayları | `GET /services/{id}/dedicated/hardware`         |
| `get_details(id)`             | Sunucu bilgisi    | `GET /services/{id}/dedicated/info`             |
| `get_os_templates(id)`        | OS şablonları     | `GET /services/{id}/dedicated/os-templates`     |
| `get_reinstall_status(id)`    | Kurulum durumu    | `GET /services/{id}/dedicated/reinstall-status` |
| `reinstall(id, data)`         | Yeniden kur       | `POST /services/{id}/dedicated/reinstall`       |
| `get_tasks(id)`               | Görevleri getir   | `GET /services/{id}/dedicated/tasks`            |

### 🛡️ Firewall Service (`client.firewall`)

| Metod                                               | Açıklama                     | Endpoint                                               |
|-----------------------------------------------------|------------------------------|--------------------------------------------------------|
| `get_attack_logs(id, ip)`                           | Saldırı kayıtlarını getir    | `GET /services/{id}/firewall/{ip}/attack-logs`         |
| `get_attack_notification_settings(id, ip)`          | Bildirim ayarları            | `GET /services/{id}/firewall/{ip}/attack-notification` |
| `update_attack_notification_settings(id, ip, data)` | Bildirim ayarlarını güncelle | `PUT /services/{id}/firewall/{ip}/attack-notification` |
| `delete_reverse_dns(id, ip)`                        | rDNS kaldır                  | `DELETE /services/{id}/firewall/{ip}/rdns`             |
| `get_reverse_dns(id, ip)`                           | rDNS bilgisi                 | `GET /services/{id}/firewall/{ip}/rdns`                |
| `upsert_reverse_dns(id, ip, rdns_data)`             | rDNS ayarla                  | `PUT /services/{id}/firewall/{ip}/rdns`                |
| `delete_rule(id, ip, rule_id)`                      | Kural sil                    | `DELETE /services/{id}/firewall/{ip}/rules/{rule_id}`  |
| `get_rules(id, ip)`                                 | Kuralları getir              | `GET /services/{id}/firewall/{ip}/rules`               |
| `create_rule(id, ip, data)`                         | Kural oluştur                | `POST /services/{id}/firewall/{ip}/rules`              |
| `get_statistics(id, ip)`                            | İstatistikleri getir         | `GET /services/{id}/firewall/{ip}/stats`               |

## 🔐 Güvenlik İpuçları

- API token'ınızı doğrudan kodda tutmayın. Ortam değişkenlerinden (env vars) veya güvenli bir yapılandırma dosyasından
  alın
- Her `ApiResponse` sonrası `.success` özelliğini kontrol edin
- Hataları uygun try-except blokları veya if-else yapılarıyla detaylı olarak yönetin

## 🚀 Performans Önerileri

- Asenkron işlemleri `asyncio.gather()` ile paralel çalıştırın
- Gecikmeleri azaltmak için `RestClientOptions` içinde timeout ve rate limit ayarlarını yapılandırın
- Uygulama başında `NodestyApiClient`'i bir kere oluşturun ve tüm uygulamanız boyunca tekrar kullanın (`async with`
  ifadesi ile otomatik kapanmasını sağlayabilirsiniz)

## 🧪 Test Örneği

```python
import asyncio
import os
from nodesty_api_client import NodestyApiClient, RestClientOptions


async def test_user_service():
    token = os.environ.get("NODESTY_TEST_TOKEN")
    if not token:
        raise ValueError("NODESTY_TEST_TOKEN ortam değişkeni ayarlanmamış.")

    options = RestClientOptions(access_token=token)
    async with NodestyApiClient(options) as client:
        response = await client.user.get_current_user()
        assert response.success, f"Test başarısız: {response.error}"
        assert response.data and "@" in response.data.email, "Kullanıcı bilgisi veya email bulunamadı."
        print("Kullanıcı servisi testi başarılı!")


if __name__ == "__main__":
    asyncio.run(test_user_service())
```

## 🐛 Sorun Giderme

**httpx.HTTPStatusError: 401 Unauthorized**

- API token'ınız geçersiz veya süresi dolmuş olabilir. Nodesty kontrol panelinden kontrol edin

**httpx.ConnectTimeout veya benzeri Timeout hataları**

- Ağ bağlantınızı ve `RestClientOptions` içindeki timeout süresini kontrol edin. Gerekirse artırın

**Too Many Requests (429 Hata)**

- API'nin rate limitine takılmış olabilirsiniz. `RestClientOptions` içindeki `rate_limit_offset` değerini artırın veya
  istekler arasında daha fazla bekleme süresi ekleyin

## 🤝 Katkıda Bulunma

1. Bu depoyu (repository) fork'layın
2. Yeni bir özellik veya hata düzeltmesi için bir branch oluşturun (`git checkout -b feature/harika-ozellik`)
3. Değişikliklerinizi yapın ve commit'leyin
4. Remote deponuza push yapın
5. Bir Pull Request (PR) gönderin

## 🔗 Bağlantılar

- [Nodesty Website](https://nodesty.com)
- [API Dökümantasyonu](https://nodesty.com/docs)

## ⭐ Destek

Bu proje faydalı olduysa bir yıldız (⭐) vererek destekleyebilirsiniz!

---

**Made with ❤️ for Nodesty Community.**