-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enable internal support for http path to connect to a bot within Dire…
…ctLineSpeech channel (#3178) * [HIGH] Bump to 4.9.1-0 (#3162) * 4.9.1-0 * Update samples * Add 4.9.0 * Redirect 4.8 to 4.8.1 * minimum changes to support HTTP path * dont set conversationId * fix token extraction * fix token renewal condition * working code with directline support * add sample with http support * add integration tests for internal http support * fix src of index-http.html * Revert "[HIGH] Bump to 4.9.1-0 (#3162)" This reverts commit 27eaf2b. * fix refresh token logic * fix eslint issues * fix more eslint issues * PR Feedback * fix build issues * fix test failures * fix tests * PR Feedback * remove sample * PR feedback * Fix credentials in test * Typo * Clean up * Add refresh token tests * fix token renewal for directline * disable test or useInternalHttpSupport when speak field si empty Co-authored-by: William Wong <compulim@users.noreply.github.com> Co-authored-by: TJ Durnford <tjdford@gmail.com> Co-authored-by: William Wong <compulim@hotmail.com>
- Loading branch information
1 parent
ed452fb
commit 367b429
Showing
12 changed files
with
354 additions
and
109 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
packages/directlinespeech/__tests__/refreshToken.authorizationToken.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
|
||
import 'global-agent/bootstrap'; | ||
|
||
import { PropertyId } from 'microsoft-cognitiveservices-speech-sdk'; | ||
import { timeouts } from './constants.json'; | ||
import createTestHarness from './utilities/createTestHarness'; | ||
import MockAudioContext from './utilities/MockAudioContext'; | ||
|
||
jest.setTimeout(timeouts.test); | ||
|
||
beforeEach(() => { | ||
global.AudioContext = MockAudioContext; | ||
}); | ||
|
||
const realSetTimeout = setTimeout; | ||
|
||
function sleep(intervalMS) { | ||
return new Promise(resolve => realSetTimeout(resolve, intervalMS)); | ||
} | ||
|
||
async function waitUntil(fn, timeout = 5000, intervalMS = 1000) { | ||
const startTime = Date.now(); | ||
|
||
while (Date.now() - startTime < timeout) { | ||
if (fn()) { | ||
return; | ||
} | ||
|
||
await sleep(intervalMS); | ||
} | ||
|
||
throw new Error('timed out'); | ||
} | ||
|
||
test('should refresh authorization token', async () => { | ||
jest.useFakeTimers('modern'); | ||
|
||
const { directLine } = await createTestHarness(); | ||
const initialAuthorizationToken = directLine.dialogServiceConnector.authorizationToken; | ||
|
||
// Wait until 2 seconds in real-time clock, to make sure the token renewed is different (JWT has a per-second timestamp). | ||
await sleep(2000); | ||
|
||
// Fast-forward 15 minutes to kick-off the token renewal | ||
jest.advanceTimersByTime(120000); | ||
|
||
// Wait for 5 seconds until the token get updated | ||
await waitUntil(() => initialAuthorizationToken !== directLine.dialogServiceConnector.authorizationToken); | ||
}); |
56 changes: 56 additions & 0 deletions
56
packages/directlinespeech/__tests__/refreshToken.directLineToken.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
|
||
import 'global-agent/bootstrap'; | ||
|
||
import { PropertyId } from 'microsoft-cognitiveservices-speech-sdk'; | ||
import { timeouts } from './constants.json'; | ||
import createTestHarness from './utilities/createTestHarness'; | ||
import MockAudioContext from './utilities/MockAudioContext'; | ||
|
||
jest.setTimeout(timeouts.test); | ||
|
||
beforeEach(() => { | ||
global.AudioContext = MockAudioContext; | ||
}); | ||
|
||
const realSetTimeout = setTimeout; | ||
|
||
function sleep(intervalMS) { | ||
return new Promise(resolve => realSetTimeout(resolve, intervalMS)); | ||
} | ||
|
||
async function waitUntil(fn, timeout = 5000, intervalMS = 1000) { | ||
const startTime = Date.now(); | ||
|
||
while (Date.now() - startTime < timeout) { | ||
if (fn()) { | ||
return; | ||
} | ||
|
||
await sleep(intervalMS); | ||
} | ||
|
||
throw new Error('timed out'); | ||
} | ||
|
||
test('should refresh Direct Line token', async () => { | ||
jest.useFakeTimers('modern'); | ||
|
||
const { directLine } = await createTestHarness({ enableInternalHTTPSupport: true }); | ||
const initialToken = directLine.dialogServiceConnector.properties.getProperty(PropertyId.Conversation_ApplicationId); | ||
|
||
// Wait until 2 seconds in real-time clock, to make sure the token renewed is different (JWT has a per-second timestamp). | ||
await sleep(2000); | ||
|
||
// Fast-forward 15 minutes to kick-off the token renewal | ||
jest.advanceTimersByTime(900000); | ||
|
||
// Wait for 5 seconds until the token get updated | ||
await waitUntil( | ||
() => | ||
initialToken !== | ||
directLine.dialogServiceConnector.properties.getProperty(PropertyId.Conversation_ApplicationId, 5000) | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
packages/directlinespeech/__tests__/utilities/createFetchCredentials.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import fetch from 'node-fetch'; | ||
|
||
const TOKEN_URL_TEMPLATE = 'https://{region}.api.cognitive.microsoft.com/sts/v1.0/issueToken'; | ||
|
||
async function fetchBaseSpeechCredentialsFromWaterBottle() { | ||
const res = await fetch('https://webchat-waterbottle.azurewebsites.net/token/speechservices'); | ||
|
||
if (!res.ok) { | ||
throw new Error(`Failed to fetch Cognitive Services Speech Services credentials, server returned ${res.status}`); | ||
} | ||
|
||
const { region, token: authorizationToken } = await res.json(); | ||
|
||
return { authorizationToken, region }; | ||
} | ||
|
||
async function fetchBaseSpeechCredentialsFromSubscriptionKey({ region, subscriptionKey }) { | ||
const res = await fetch(TOKEN_URL_TEMPLATE.replace(/\{region\}/u, region), { | ||
headers: { | ||
'Ocp-Apim-Subscription-Key': subscriptionKey | ||
}, | ||
method: 'POST' | ||
}); | ||
|
||
if (!res.ok) { | ||
throw new Error(`Failed to fetch authorization token, server returned ${res.status}`); | ||
} | ||
|
||
return { | ||
authorizationToken: await res.text(), | ||
region | ||
}; | ||
} | ||
|
||
async function fetchDirectLineTokenFromWaterBottle() { | ||
const directLineTokenResult = await fetch('https://webchat-waterbottle.azurewebsites.net/token/directline'); | ||
|
||
if (!directLineTokenResult.ok) { | ||
throw new Error( | ||
`Failed to fetch Cognitive Services Direct Line credentials, server returned ${directLineTokenResult.status}` | ||
); | ||
} | ||
|
||
const { token: directLineToken } = await directLineTokenResult.json(); | ||
|
||
return { directLineToken }; | ||
} | ||
|
||
async function fetchDirectLineCredentialsFromDirectLineSecret(channelSecret) { | ||
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', { | ||
headers: { | ||
Authorization: `Bearer ${channelSecret}` | ||
}, | ||
method: 'POST' | ||
}); | ||
|
||
if (!res.ok) { | ||
throw new Error(`Failed to fetch authorization token for Direct Line, server returned ${res.status}`); | ||
} | ||
|
||
const { token } = await res.json(); | ||
|
||
return { directLineToken }; | ||
} | ||
|
||
export default function createFetchCredentials({ enableInternalHTTPSupport } = {}) { | ||
let cachedCredentials; | ||
|
||
setInterval(() => { | ||
cachedCredentials = null; | ||
}, 120000); | ||
|
||
return () => { | ||
if (!cachedCredentials) { | ||
const { | ||
SPEECH_SERVICES_DIRECT_LINE_SECRET, | ||
SPEECH_SERVICES_REGION, | ||
SPEECH_SERVICES_SUBSCRIPTION_KEY | ||
} = process.env; | ||
|
||
let baseCredentialsPromise; | ||
let additionalCredentialsPromise; | ||
|
||
if (SPEECH_SERVICES_REGION && SPEECH_SERVICES_SUBSCRIPTION_KEY) { | ||
baseCredentialsPromise = fetchBaseSpeechCredentialsFromSubscriptionKey({ | ||
region: SPEECH_SERVICES_REGION, | ||
subscriptionKey: SPEECH_SERVICES_SUBSCRIPTION_KEY | ||
}); | ||
|
||
if (enableInternalHTTPSupport) { | ||
if (!SPEECH_SERVICES_DIRECT_LINE_SECRET) { | ||
throw new Error( | ||
`Failed to fetch Direct Line token as SPEECH_SERVICES_DIRECT_LINE_SECRET environment variable is not set` | ||
); | ||
} | ||
|
||
additionalCredentialsPromise = fetchDirectLineCredentialsFromDirectLineSecret( | ||
SPEECH_SERVICES_DIRECT_LINE_SECRET | ||
); | ||
} | ||
} else { | ||
baseCredentialsPromise = fetchBaseSpeechCredentialsFromWaterBottle(); | ||
|
||
if (enableInternalHTTPSupport) { | ||
additionalCredentialsPromise = fetchDirectLineTokenFromWaterBottle(); | ||
} | ||
} | ||
|
||
cachedCredentials = (async () => ({ | ||
...(await baseCredentialsPromise), | ||
...(await (additionalCredentialsPromise || {})) | ||
}))(); | ||
} | ||
|
||
return cachedCredentials; | ||
}; | ||
} |
12 changes: 8 additions & 4 deletions
12
packages/directlinespeech/__tests__/utilities/createTestHarness.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.