Skip to content

Commit

Permalink
Merge pull request #91 from NabuCasa/dev
Browse files Browse the repository at this point in the history
Release 0.18
  • Loading branch information
pvizeli authored Oct 2, 2019
2 parents 2be3bd2 + 0d69e31 commit 1d4f8c2
Show file tree
Hide file tree
Showing 26 changed files with 897 additions and 595 deletions.
7 changes: 4 additions & 3 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
FROM python:3.7

WORKDIR /workspace
WORKDIR /workspaces

# Install Python dependencies from requirements.txt if it exists
COPY requirements_tests.txt /workspace/
RUN pip3 install -r requirements_tests.txt
COPY requirements_tests.txt .
RUN pip3 install -r requirements_tests.txt tox \
&& rm -f requirements_tests.txt

# Set the default shell to bash instead of sh
ENV SHELL /bin/bash
6 changes: 4 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
],
"extensions": [
"ms-python.python",
"ms-azure-devops.azure-pipelines"
"visualstudioexptteam.vscodeintellicode",
"ms-azure-devops.azure-pipelines",
"esbenp.prettier-vscode"
],
"settings": {
"python.pythonPath": "/usr/local/bin/python",
Expand All @@ -27,4 +29,4 @@
"files.trimTrailingWhitespace": true,
"terminal.integrated.shell.linux": "/bin/bash"
}
}
}
29 changes: 29 additions & 0 deletions azure-pipelines-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# https://dev.azure.com/NabuCasa/OpenSource

trigger:
branches:
include:
- dev
pr:
- dev

jobs:

- job: "Tox"
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
Python36:
python.version: '3.6'
Python37:
python.version: '3.7'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python $(python.version)'
inputs:
versionSpec: '$(python.version)'
- script: pip install tox
displayName: 'Install Tox'
- script: tox
displayName: 'Run Tox'
41 changes: 41 additions & 0 deletions azure-pipelines-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# https://dev.azure.com/NabuCasa/OpenSource

trigger:
tags:
include:
- '*'
pr: none

variables:
- group: twine


jobs:

- job: 'Release'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python 3.7'
inputs:
versionSpec: '3.7'
- script: |
setup_version="$(python setup.py -V)"
branch_version="$(Build.SourceBranchName)"
if [ "${setup_version}" != "${branch_version}" ]; then
echo "Version of tag ${branch_version} don't match with ${setup_version}!"
exit 1
fi
displayName: 'Check version of branch/tag'
- script: pip install twine wheel
displayName: 'Install twine'
- script: python setup.py sdist bdist_wheel
displayName: 'Build package'
- script: |
export TWINE_USERNAME="$(twineUser)"
export TWINE_PASSWORD="$(twinePassword)"
twine upload dist/*
displayName: 'Upload pypi'
87 changes: 0 additions & 87 deletions azure-pipelines.yml

This file was deleted.

10 changes: 9 additions & 1 deletion hass_nabucasa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .cloudhooks import Cloudhooks
from .auth import CognitoAuth
from .const import CONFIG_DIR, MODE_DEV, SERVERS, STATE_CONNECTED
from .google_report_state import GoogleReportState
from .iot import CloudIoT
from .remote import RemoteUI
from .utils import parse_date, utcnow, UTC
Expand All @@ -30,6 +31,7 @@ def __init__(
user_pool_id=None,
region=None,
relayer=None,
google_actions_report_state_url=None,
google_actions_sync_url=None,
subscription_info_url=None,
cloudhook_create_url=None,
Expand All @@ -44,6 +46,7 @@ def __init__(
self.access_token = None
self.refresh_token = None
self.iot = CloudIoT(self)
self.google_report_state = GoogleReportState(self)
self.cloudhooks = Cloudhooks(self)
self.remote = RemoteUI(self)
self.auth = CognitoAuth(self)
Expand All @@ -53,6 +56,7 @@ def __init__(
self.user_pool_id = user_pool_id
self.region = region
self.relayer = relayer
self.google_actions_report_state_url = google_actions_report_state_url
self.google_actions_sync_url = google_actions_sync_url
self.subscription_info_url = subscription_info_url
self.cloudhook_create_url = cloudhook_create_url
Expand All @@ -67,6 +71,9 @@ def __init__(
self.user_pool_id = info["user_pool_id"]
self.region = info["region"]
self.relayer = info["relayer"]
self.google_actions_report_state_url = info[
"google_actions_report_state_url"
]
self.google_actions_sync_url = info["google_actions_sync_url"]
self.subscription_info_url = info["subscription_info_url"]
self.cloudhook_create_url = info["cloudhook_create_url"]
Expand Down Expand Up @@ -134,14 +141,15 @@ def run_executor(self, callback: Callable, *args) -> asyncio.Future:

async def fetch_subscription_info(self):
"""Fetch subscription info."""
await self.run_executor(self.auth.check_token)
await self.auth.async_check_token()
return await self.websession.get(
self.subscription_info_url, headers={"authorization": self.id_token}
)

async def logout(self) -> None:
"""Close connection and remove all credentials."""
await self.iot.disconnect()
await self.google_report_state.disconnect()

self.id_token = None
self.access_token = None
Expand Down
19 changes: 18 additions & 1 deletion hass_nabucasa/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import warrant
from warrant.exceptions import ForceChangePasswordException

from .const import MESSAGE_AUTH_FAIL

_LOGGER = logging.getLogger(__name__)


Expand Down Expand Up @@ -137,7 +139,22 @@ def login(self, email, password):
self.cloud.refresh_token = cognito.refresh_token
self.cloud.write_user_info()

def check_token(self):
async def async_check_token(self):
"""Check that the token is valid."""
try:
await self.cloud.run_executor(self._check_token)
except Unauthenticated as err:
_LOGGER.error("Unable to refresh token: %s", err)

self.cloud.client.user_message(
"cloud_subscription_expired", "Home Assistant Cloud", MESSAGE_AUTH_FAIL
)

# Don't await it because it could cancel this task
self.cloud.run_task(self.cloud.logout())
raise

def _check_token(self):
"""Check that the token is valid and verify if needed."""
cognito = self._cognito(
access_token=self.cloud.access_token, refresh_token=self.cloud.refresh_token
Expand Down
13 changes: 13 additions & 0 deletions hass_nabucasa/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

if TYPE_CHECKING:
from . import Cloud
# pylint: disable=import-error
from homeassistant.components.google.helpers import AbstractConfig as GoogleConfig
from homeassistant.components.alexa.config import AbstractConfig as AlexaConfig


class CloudClient:
Expand Down Expand Up @@ -42,6 +45,16 @@ def remote_autostart(self) -> bool:
"""Return true if we want start a remote connection."""
raise NotImplementedError()

@property
def alexa_config(self) -> "AlexaConfig":
"""Return Alexa config."""
raise NotImplementedError()

@property
def google_config(self) -> "GoogleConfig":
"""Return Google config."""
raise NotImplementedError()

async def async_initialize(self, cloud: "Cloud") -> None:
"""Initialize the client."""
raise NotImplementedError()
Expand Down
2 changes: 1 addition & 1 deletion hass_nabucasa/cloud_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def _check_token(func):
@wraps(func)
async def check_token(cloud, *args):
"""Validate token, then call func."""
await cloud.run_executor(cloud.auth.check_token)
await cloud.auth.async_check_token()
return await func(cloud, *args)

return check_token
Expand Down
1 change: 1 addition & 0 deletions hass_nabucasa/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"user_pool_id": "us-east-1_87ll5WOP8",
"region": "us-east-1",
"relayer": "wss://cloud.nabucasa.com/websocket",
"google_actions_report_state_url": "remotestate.nabucasa.com",
"google_actions_sync_url": (
"https://24ab3v80xd.execute-api.us-east-1."
"amazonaws.com/prod/smart_home_sync"
Expand Down
69 changes: 69 additions & 0 deletions hass_nabucasa/google_report_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Module to handle Google Report State."""
import asyncio
from asyncio.queues import Queue
import logging

from . import iot_base

_LOGGER = logging.getLogger(__name__)
MAX_PENDING = 100


class GoogleReportState(iot_base.BaseIoT):
"""Report states to Google.
Uses a queue to send messages.
"""

def __init__(self, cloud):
"""Initialize Google Report State."""
super().__init__(cloud)
self._connect_lock = asyncio.Lock()
self._to_send = Queue(100)
self._message_sender_task = None
self.register_on_connect(self._async_on_connect)
self.register_on_disconnect(self._async_on_disconnect)

@property
def package_name(self) -> str:
"""Return the package name for logging."""
return __name__

@property
def ws_server_url(self) -> str:
"""Server to connect to."""
return self.cloud.google_actions_report_state_url

async def async_send_message(self, msg):
"""Send a message."""
# Since connect is async, guard against send_message called twice in parallel.
async with self._connect_lock:
if self.state == iot_base.STATE_DISCONNECTED:
self.cloud.run_task(self.connect())
# Give connect time to start up and change state.
await asyncio.sleep(0)

if self._to_send.full():
self._to_send.get_nowait()
self._to_send.put_nowait(msg)

def async_handle_message(self, msg):
"""Handle a message."""
self._logger.warning("Got unhandled message: %s", msg)

async def _async_on_connect(self):
"""On Connect handler."""
self._message_sender_task = self.cloud.run_task(self._async_message_sender())

async def _async_on_disconnect(self):
"""On disconnect handler."""
self._message_sender_task.cancel()
self._message_sender_task = None

async def _async_message_sender(self):
"""Start sending messages."""
try:
while True:
await self.async_send_json_message(await self._to_send.get())
except asyncio.CancelledError:
pass
Loading

0 comments on commit 1d4f8c2

Please sign in to comment.