import ssl
import grpc
import time
import threading
from abc import ABCMeta, abstractmethod


def get_creds(host, port, token, root_cert=None):
    if root_cert is not None:
        with open(root_cert, 'rb') as f:
            cert = f.read()
    else:
        cert = ssl.get_server_certificate((host, port)).encode('utf-8')
    creds = grpc.ssl_channel_credentials(cert)
    call = grpc.access_token_call_credentials(token)
    creds_new = grpc.composite_channel_credentials(creds, call)
    return creds_new


class CachedToken:
    __metaclass__ = ABCMeta

    lock = threading.Lock()
    expire_at = -1
    token = None

    @classmethod
    def get(cls, *args, **kwargs):
        with cls.lock:
            if cls.expire_at <= time.time():  # token expires
                cls.token, cls.expire_at = cls._get_with_no_cache(*args, **kwargs)
            return cls.token

    @abstractmethod
    def _get_with_no_cache():
        """get necessary token. Return token and expiration time"""
