| """Utility class for sending requests to BonD, adding and controlling bots.""" |
| |
| from __future__ import absolute_import |
| from __future__ import division |
| from __future__ import print_function |
| |
| import json |
| import logging |
| import requests |
| |
| from datetime import datetime |
| from oauth2client.client import GoogleCredentials |
| |
| |
| _BOND_API_URL = 'https://bond-pa.sandbox.googleapis.com' |
| _HANGOUTS_API_URL = 'https://www.googleapis.com/hangouts/v1_meetings_preprod/' |
| _MEETINGS_API_URL = 'https://preprod-meetings.sandbox.googleapis.com' |
| |
| _TOKEN_TTL_SECONDS = 3500 |
| |
| # See https://crbug.com/874835 for details on the credentials files. |
| _SERVICE_CREDS_FILE = '/creds/service_accounts/bond_service_account.json' |
| |
| |
| class BondHttpApi(object): |
| """Utility class for sending requests to BonD for bots.""" |
| |
| def __init__(self): |
| self._last_token_request_time = None |
| self._last_token = None |
| |
| def GetAvailableWorkers(self): |
| """Gets the number of available workers for a conference.""" |
| token = self._GetAccessToken() |
| resp = requests.get( |
| '%s/v1/workers:count' % _BOND_API_URL, |
| headers={ |
| 'Content-Type': 'application/json', |
| 'Authorization': 'Bearer %s' % token |
| }) |
| return json.loads(resp.text)["numOfAvailableWorkers"] |
| |
| def CreateConference(self): |
| """Creates a conference. |
| |
| Returns: |
| The meeting code of the created conference. |
| """ |
| token = self._GetAccessToken() |
| |
| request_data = { |
| 'conference_type': 'THOR', |
| 'backend_options': { |
| 'mesi_apiary_url': _HANGOUTS_API_URL, |
| 'mas_one_platform_url': _MEETINGS_API_URL |
| }, |
| } |
| |
| resp = requests.post( |
| '%s/v1/conferences:create' % _BOND_API_URL, |
| headers={ |
| 'Content-Type': 'application/json', |
| 'Authorization': 'Bearer %s' % token, |
| }, |
| data=json.dumps(request_data)) |
| json_response = json.loads(resp.text) |
| logging.info("CreateConference response: %s", json_response) |
| return json_response["conference"]["conferenceCode"] |
| |
| def ExecuteScript(self, script, meeting_code): |
| """Executes the specified script. |
| |
| Args: |
| script: Script to execute. |
| meeting_code: The meeting to execute the script for. |
| |
| Returns: |
| RunScriptRequest denoting failure or success of the request. |
| """ |
| token = self._GetAccessToken() |
| |
| request_data = { |
| 'script': script, |
| 'conference': { |
| 'conference_code': meeting_code |
| } |
| } |
| |
| resp = requests.post( |
| '%s/v1/conference/%s/script' % (_BOND_API_URL, meeting_code), |
| headers={ |
| 'Content-Type': 'application/json', |
| 'Authorization': 'Bearer %s' % token, |
| }, |
| data=json.dumps(request_data)) |
| |
| json_response = json.loads(resp.text) |
| logging.info("ExecuteScript response: %s", json_response) |
| return json_response['success'] |
| |
| |
| def AddBotsRequest(self, meeting_code, number_of_bots, ttl_secs): |
| """Adds a number of bots to a meeting for a specified period of time. |
| |
| Args: |
| meeting_code: The meeting to join. |
| number_of_bots: The number of bots to add to the meeting. |
| ttl_secs: The time in seconds that the bots will stay in the meeting after |
| joining. |
| |
| Returns: |
| List of IDs of the started bots. |
| """ |
| token = self._GetAccessToken() |
| |
| request_data = { |
| 'num_of_bots': number_of_bots, |
| 'ttl_secs': ttl_secs, |
| 'video_call_options': {}, |
| 'media_options': { |
| 'audio_file_path': "audio_32bit_48k_stereo.raw", |
| 'mute_audio': True, |
| 'video_file_path': "jamboard_two_far_video_hd.1280_720.yuv", |
| 'video_fps': 30, |
| 'mute_video': False |
| }, |
| 'backend_options': { |
| 'mesi_apiary_url': _HANGOUTS_API_URL, |
| 'mas_one_platform_url': _MEETINGS_API_URL |
| }, |
| 'conference': { |
| 'conference_code': meeting_code |
| }, |
| 'bot_type': "MEETINGS" |
| } |
| |
| resp = requests.post( |
| '%s/v1/conference/%s/bots:add' % (_BOND_API_URL, meeting_code), |
| headers={ |
| 'Content-Type': 'application/json', |
| 'Authorization': 'Bearer %s' % token |
| }, |
| data=json.dumps(request_data)) |
| |
| json_response = json.loads(resp.text) |
| logging.info("AddBotsRequest response: %s", json_response) |
| return json_response["botIds"] |
| |
| def _GetAccessToken(self): |
| if self._last_token is None or self._CheckTokenExpired(): |
| credentials = self._CreateApiCredentials() |
| scope = 'https://www.googleapis.com/auth/meetings' |
| credentials = credentials.create_scoped(scope) |
| self._last_token_request_time = datetime.now() |
| self._last_token = credentials.get_access_token().access_token |
| return self._last_token |
| |
| def _CreateApiCredentials(self): |
| return GoogleCredentials.from_stream(_SERVICE_CREDS_FILE) |
| |
| def _CheckTokenExpired(self): |
| elapsed = datetime.now() - self._last_token_request_time |
| return elapsed.total_seconds() > _TOKEN_TTL_SECONDS |