Skip to content

Commit

Permalink
[repo] chore: add User-Agent to responses (#1285)
Browse files Browse the repository at this point in the history
## Linked issues

closes: #1281 

## Details

add `User-Agent` header to responses for telemetry purposes.
  • Loading branch information
aacebo authored Feb 15, 2024
1 parent 289917f commit c95b97d
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http.Headers;
Expand Down Expand Up @@ -42,6 +44,15 @@ public TeamsAdapter(
{
HttpClientFactory = new TeamsHttpClientFactory(httpClientFactory);
}

/// <inheritdoc />
public new async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default)
{
string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
ProductInfoHeaderValue productInfo = new("teamsai-dotnet", version);
httpResponse.Headers.Add("User-Agent", productInfo.ToString());
await base.ProcessAsync(httpRequest, httpResponse, bot, cancellationToken);
}
}

internal class TeamsHttpClientFactory : IHttpClientFactory
Expand Down
2 changes: 2 additions & 0 deletions js/packages/teams-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
},
"devDependencies": {
"@types/assert": "^1.5.10",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.4",
"@types/mocha": "^10.0.6",
"@types/node": "^20.11.19",
"@types/uuid": "^9.0.8",
"eslint": "^8.56.0",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"mocha": "10.3.0",
"nyc": "^15.1.0",
Expand Down
2 changes: 1 addition & 1 deletion js/packages/teams-ai/src/AdaptiveCards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('AdaptiveCards', () => {
let selector: RouteSelector;
let handler: any;
let addRouteStub: sinon.SinonStub;
let adapter = new TestAdapter();
const adapter = new TestAdapter();

beforeEach(() => {
app = new Application();
Expand Down
72 changes: 72 additions & 0 deletions js/packages/teams-ai/src/TeamsAdapter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import http from 'http';
import assert from 'assert';
import sinon from 'sinon';
import axios from 'axios';
import express from 'express';

import { TeamsAdapter } from './TeamsAdapter';

describe('TeamsAdapter', () => {
let sandbox: sinon.SinonSandbox;
const app = express();
let server: http.Server;
let adapter: TeamsAdapter;

beforeEach(() => {
sandbox = sinon.createSandbox();
adapter = new TeamsAdapter();

app.post('/api/messages', async (req, res) => {
await adapter.process(req, res, async () => {});
});

server = app.listen(80);
});

afterEach(() => {
sandbox.reset();
server.close();
});

describe('process', () => {
it('should add `User-Agent` header to response', async () => {
sandbox.stub(adapter, <any>'processActivity').resolves({ status: 200 });
let userAgent: string | undefined;

try {
const res = await axios.post('/api/messages', {
type: 'invoke',
localTimezone: 'America/Los_Angeles',
callerId: 'test',
serviceUrl: 'test',
channelId: 'test',
from: {
id: '123456',
name: 'test'
},
conversation: {
id: '123456',
name: 'test',
conversationType: 'test',
isGroup: false
},
recipient: {
id: '123456',
name: 'test'
},
text: '',
label: 'invoke',
valueType: 'invoke'
});

userAgent = res.headers['user-agent'];
} catch (err) {
if (err instanceof axios.AxiosError) {
userAgent = err.response?.headers['user-agent'];
}
}

assert.strict.equal(userAgent, adapter.userAgent);
});
});
});
33 changes: 32 additions & 1 deletion js/packages/teams-ai/src/TeamsAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {
ConfigurationBotFrameworkAuthentication,
ConfigurationBotFrameworkAuthenticationOptions,
ConfigurationServiceClientCredentialFactory,
ConfigurationServiceClientCredentialFactoryOptions
ConfigurationServiceClientCredentialFactoryOptions,
Request,
Response,
TurnContext
} from 'botbuilder';

import {
Expand All @@ -27,6 +30,7 @@ import {
} from 'botframework-connector';

import packageInfo from '../package.json';
import { INodeSocket, INodeBuffer } from 'botframework-streaming';

const USER_AGENT = `teamsai-js/${packageInfo.version}`;

Expand All @@ -39,6 +43,10 @@ export class TeamsAdapter extends CloudAdapter {
*/
public readonly credentialsFactory: ServiceClientCredentialsFactory;

public get userAgent(): string {
return USER_AGENT;
}

constructor(
readonly botFrameworkAuthConfig?: ConfigurationBotFrameworkAuthenticationOptions,
credentialsFactory?: ServiceClientCredentialsFactory,
Expand All @@ -65,4 +73,27 @@ export class TeamsAdapter extends CloudAdapter {
botFrameworkAuthConfig as ConfigurationServiceClientCredentialFactoryOptions
);
}

async process(req: Request, res: Response, logic: (context: TurnContext) => Promise<void>): Promise<void>;
async process(
req: Request,
socket: INodeSocket,
head: INodeBuffer,
logic: (context: TurnContext) => Promise<void>
): Promise<void>;
async process(
req: Request,
resOrSocket: Response | INodeSocket,
logicOrHead: ((context: TurnContext) => Promise<void>) | INodeBuffer,
maybeLogic?: (context: TurnContext) => Promise<void>
): Promise<void> {
if ('header' in resOrSocket && typeof logicOrHead === 'function') {
resOrSocket.header('User-Agent', USER_AGENT);
return super.process(req, resOrSocket, logicOrHead);
}

if ('connecting' in resOrSocket && typeof logicOrHead !== 'function' && !!maybeLogic) {
return super.process(req, resOrSocket, logicOrHead, maybeLogic);
}
}
}

0 comments on commit c95b97d

Please sign in to comment.