""" ╔══════════════════════════════════════════════════════════════════╗ ║ VTPRestAPI — Python Client ║ ║ Install: pip install requests ║ ╚══════════════════════════════════════════════════════════════════╝ FLOW: 1. api = VTPApiClient('http://vivekamih.gotdns.com:8033/api/') 2. api.login('username', 'password') # get API Key 3. api.get('vtp/valid-trading-date') # use API Key 4. Session expires → auto re-login on next call """ import requests import json from datetime import datetime, timezone class VTPApiClient: # ── Server endpoints ────────────────────────────────────────────── LOCAL = 'http://localhost:51631/api/' TEST = 'http://vivekamih.gotdns.com:8033/api/' PROD = 'http://vtpapi.vivekam.com/api/' def __init__(self, base_url=None): self.base_url = (base_url or self.TEST).rstrip('/') + '/' self.session_token = None self.expires_at = None self.current_user = None self.current_role = None self._saved_user = None self._saved_pass = None self._session = requests.Session() self._session.headers.update({ 'Content-Type': 'application/json', 'Accept': 'application/json' }) @property def is_logged_in(self): if not self.session_token or not self.expires_at: return False return datetime.now(timezone.utc) < self.expires_at # ══════════════════════════════════════════════════════════════════ # AUTH # ══════════════════════════════════════════════════════════════════ def login(self, username: str, password: str) -> dict: """Login and get session API Key. Call once before any API.""" res = self._session.post( self.base_url + 'auth/login', json={'username': username, 'password': password}) data = res.json() if not res.ok or not data.get('success'): raise Exception(f"Login failed: {data.get('message')}") self.session_token = data['sessionToken'] self.expires_at = datetime.fromisoformat( data['expiresAt'].replace('Z', '+00:00')) self.current_user = data['username'] self.current_role = data['role'] self._saved_user = username self._saved_pass = password # Attach token to all future requests self._session.headers.update({'X-Session-Token': self.session_token}) print(f"[VTPApi] ✅ Logged in as [{data['role']}] {data['username']}") print(f"[VTPApi] 🔑 API Key: {self.session_token}") print(f"[VTPApi] ⏰ Expires: {self.expires_at.astimezone().strftime('%H:%M:%S')}") return data def logout(self): """Logout and clear session.""" try: self._session.post(self.base_url + 'auth/logout') except Exception: pass self.session_token = None self._session.headers.pop('X-Session-Token', None) print('[VTPApi] Logged out.') # ══════════════════════════════════════════════════════════════════ # HTTP METHODS — auto refresh session on 401 # ══════════════════════════════════════════════════════════════════ def get(self, endpoint: str, params: dict = None): return self._call('GET', endpoint, params=params) def post(self, endpoint: str, body: dict = None): return self._call('POST', endpoint, body=body) def put(self, endpoint: str, body: dict = None): return self._call('PUT', endpoint, body=body) def delete(self, endpoint: str): return self._call('DELETE', endpoint) # ══════════════════════════════════════════════════════════════════ # INTERNALS # ══════════════════════════════════════════════════════════════════ def _call(self, method: str, endpoint: str, params=None, body=None, is_retry=False): self._ensure_session() url = self.base_url + endpoint res = self._session.request( method, url, params=params, json=body if body else None) # Session expired → re-login and retry ONCE if res.status_code == 401 and not is_retry: print('[VTPApi] ⚠️ Session expired. Re-logging in…') self.login(self._saved_user, self._saved_pass) return self._call(method, endpoint, params, body, True) try: data = res.json() except Exception: data = res.text if not res.ok: msg = data.get('message', str(data)) if isinstance(data, dict) else data raise Exception(f'[VTPApi] {res.status_code}: {msg}') return data def _ensure_session(self): if self.is_logged_in: return if self._saved_user: print('[VTPApi] Session expired. Auto re-login…') self.login(self._saved_user, self._saved_pass) else: raise Exception( 'Not logged in. Call api.login(username, password) first.') def __enter__(self): return self def __exit__(self, *args): self.logout() # ══════════════════════════════════════════════════════════════════════ # QUICK-START DEMO # ══════════════════════════════════════════════════════════════════════ if __name__ == '__main__': # ── 1. Create client ────────────────────────────────────────────── with VTPApiClient(VTPApiClient.TEST) as api: # ── 2. Login → get API Key ──────────────────────────────────── api.login('admin', 'Admin@123') # ── 3. Call APIs — token sent automatically ─────────────────── # GET (no params) trading_date = api.get('vtp/valid-trading-date') print('Valid Trading Date:', json.dumps(trading_date, indent=2)) # GET with query params clients = api.get('vtp/clients-by-product', params={'productId': 116}) print('Clients:', json.dumps(clients, indent=2)) # GET with multiple params ledger = api.get('vtp/member-ledger', params={'memberId': 135, 'partnerId': 1}) print('Member Ledger:', json.dumps(ledger, indent=2)) # POST with body bill = api.post('vtp/bill-summary', { 'MpcId': 1234, 'Date': datetime.today().strftime('%Y-%m-%d'), 'BillType': 'Q' }) print('Bill Summary:', json.dumps(bill, indent=2)) # ── 4. Logout handled automatically by 'with' block ──────────