Source code for nrgpy.cloud_api.auth
try:
from nrgpy import logger
except ImportError:
pass
from nrgpy import token_file
import base64
from datetime import datetime, timedelta
from importlib.metadata import version
import json
from packaging.version import parse as parse_version
import pickle
import requests
import traceback
cloud_url_base = "https://cloud-api.nrgsystems.com/nrgcloudcustomerapi/"
token_url = "token"
convert_url = "data/convert"
export_url = "data/export"
create_export_job_url = "data/createexportjob"
export_job_url = "data/exportjob"
import_url = "data/import"
sites_url = "sites"
[docs]class CloudApi(object):
"""
Parent class for NRG Cloud API functionality
nrgpy simplifies usage of the NRG Cloud APIs. See the documentation for the
cloud_api.sites, .export, and .convert modules for more information.
For non-nrgpy implementations, the following Usage information may be
helpful.
The base url for the NRG Cloud APIs is
https://cloud-api.nrgsystems.com/nrgcloudcustomerapi/
Use client ID and secret to obtain a bearer token at the /token endpoint.
This token is good for 24 hours.
You will be limited to creating 10 tokens per day, though normally one
token should suffice, so please cache. nrgpy's cloud_api modules will
automatically manage bearer tokens, refreshing only when necessary.
Endpoints:
base
https://cloud-api.nrgsystems.com/nrgcloudcustomerapi/
/token
for accessing bearer token. Client ID and Secret required.
/sites
Get list of sites. Bearer token required
/convert
Convert RLD file to TXT. Bearer token required
/export
Export TXT or RLD files for a given date range. NEC files may be used
to format TXT outputs. Bearer token required.
"""
def __init__(
self,
client_id: str = "",
client_secret: str = "",
url_base: str = cloud_url_base,
):
logger.debug(f"cloud base: {url_base}")
self.client_id = client_id
self.client_secret = client_secret
self.user_agent = f"nrgpy-{version('nrgpy')}"
self.token_file_name = token_file + "_" + self.client_id[:10]
self.url_base = url_base
self.token_url = url_base + token_url
self.convert_url = url_base + convert_url
self.export_url = url_base + export_url
self.create_export_job_url = url_base + create_export_job_url
self.export_job_url = url_base + export_job_url
self.import_url = url_base + import_url
self.sites_url = url_base + sites_url
if self.client_id and self.client_secret:
self.maintain_session_token()
else:
print(
"[Access error] Valid credentials are required.\n\nPlease visit https://cloud.nrgsystems.com/data-manager/api-setup\nto access your API credentials" # noqa: E501
)
logger.error(
"[Access error] Valid credentials are required. Please visit https://cloud.nrgsystems.com/data-manager/api-setup to access your API credentials" # noqa: E501
)
[docs] def request_session_token(self) -> None:
"""Generates a new session token for convert service api
Requires an active account with NRG Cloud. To sign
up for a free account, go to:
https://cloud.nrgsystems.com
Client ID and Secret can be accessed here:
https://cloud.nrgsystems.com/data-manager/api-setup
Parameters
----------
client_id : str
obtained from NRG Systems
client_secret : str
Returns
-------
session_token : str
valid for 24 hour
session_start_time : datetime
start time of 24 hour countdown
"""
logger.debug("session token requested")
print(
"{} | Requesting session token ... ".format(
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
),
end="",
flush=True,
)
request_token_header = {
"content-type": "application/json",
"user-agent": self.user_agent,
}
request_payload = {
"clientId": "{}".format(self.client_id),
"clientSecret": "{}".format(self.client_secret),
}
self.resp = requests.post(
data=json.dumps(request_payload),
headers=request_token_header,
url=self.token_url,
)
self.session_start_time = datetime.now()
try:
self.api_version = parse_version(self.resp.headers["customerapi-version"])
except Exception:
self.api_version = parse_version("1.8.0.0")
logger.info(f"customer api version {self.api_version}")
if self.resp.status_code == 200:
print("[OK]")
logger.info("new session token OK")
self.session_token = json.loads(self.resp.text)["apiToken"]
else:
logger.error("unable to get session token")
logger.debug(f"{self.resp.text}")
print("[FAILED] | unable to get session token.")
self.session_token = False
[docs] def token_valid(self) -> bool:
"""check if token is still valid
Parameters
----------
session_start_time : datetime
generated at time of token request
Returns
-------
status : bool
true if still valid, false if expired
"""
if datetime.now() < self.session_start_time + timedelta(hours=22):
if self.session_token is not False:
return True
return False
[docs] def save_token(self) -> None:
"""save session token in token pickle file"""
with open(self.token_file_name, "wb") as f:
pickle.dump(
[self.session_token, self.session_start_time, self.api_version], f
)
[docs] def load_token(self) -> None:
"""read session token from pickle file"""
with open(self.token_file_name, "rb") as f:
self.session_token, self.session_start_time, self.api_version = pickle.load(
f
)
[docs] def maintain_session_token(self) -> None:
"""maintain a current/valid session token for data service api"""
try:
self.load_token()
if not self.token_valid():
self.request_session_token()
self.save_token()
except (FileNotFoundError, ValueError):
self.request_session_token()
self.save_token()
self.headers = {
"Authorization": "Bearer {}".format(self.session_token),
"user-agent": self.user_agent,
}
[docs] def prepare_file_bytes(self, filename: str = "") -> bytes:
file_bytes = base64.encodebytes(open(filename, "rb").read())
return file_bytes
[docs]def is_authorized(resp) -> bool:
if (
resp.status_code == 401
or resp.status_code == 400
and "has already been imported" not in resp.text
):
try:
logger.error(json.loads(resp.text)["apiResponseMessage"])
print(json.loads(resp.text)["apiResponseMessage"])
except Exception:
logger.error("Unable to process request")
logger.debug(traceback.format_exc())
print("Unable to complete request. Check nrgpy log file for details")
return False
return True
cloud_api = CloudApi