Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add analytics to the gateway #3

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
5 changes: 1 addition & 4 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
import { TextEncoder, TextDecoder } from 'util';

global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder as any;
// any jest related setup here
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@
}
],
"devDependencies": {
"@cloudflare/workers-types": "^4.20230214.0",
"@cloudflare/workers-types": "^4.20240117.0",
"@ensdomains/ens-contracts": "^0.0.21",
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/dns-packet": "^5.2.4",
"@types/dns-packet": "^5.6.4",
"@types/express": "^4.17.21",
"@types/supertest": "^2.0.11",
"bundlesize2": "^0.0.31",
"chai": "^4.3.7",
Expand All @@ -73,8 +74,9 @@
},
"dependencies": {
"@chainlink/ccip-read-server": "^0.2.1",
"@ensdomains/ccip-read-cf-worker": "^0.0.1",
"@ensdomains/ccip-read-cf-worker": "^0.0.3",
"@ensdomains/dnsprovejs": "^0.4.1",
"@ensdomains/server-analytics": "^0.0.1-alpha.2",
"dotenv": "^16.0.3",
"ethers": "^5.7.2",
"node-fetch": "2.6.1"
Expand Down
72 changes: 59 additions & 13 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ import { DNSProver } from '@ensdomains/dnsprovejs';
import { ethers } from 'ethers';
import * as packet from 'dns-packet';
import * as qTypes from 'dns-packet/types';
import { serializeError } from './utils';

export function makeApp(
sendQuery: ConstructorParameters<typeof DNSProver>[0],
path: string,
Server: any
Server: any,
trackEvent?: Function
) {
const prover = new DNSProver(sendQuery);
const emptyRRSet = [
[
{
rrset: [],
sig: [],
},
],
];

const server = new Server();
const abi = [
Expand All @@ -19,20 +29,56 @@ export function makeApp(
type: 'resolve',
func: async (args: ethers.utils.Result) => {
const [name, qtype] = args;
const decodedName = packet.name.decode(
const decodedName = (packet as any).name.decode(
Buffer.from(name.slice(2), 'hex')
);
const result = await prover.queryWithProof(
qTypes.toString(qtype),
decodedName
);
const ret = Array.prototype
.concat(result.proofs, [result.answer])
.map(entry => ({
rrset: entry.toWire(),
sig: entry.signature.data.signature,
}));
return [ret];

if (
decodedName.split('.').length < 2 ||
decodedName.startsWith('.') ||
decodedName.endsWith('.')
) {
return emptyRRSet;
}

if (trackEvent) {
trackEvent(
'resolve',
{
props: { name: decodedName, qtype: qTypes.toString(qtype) },
},
true
);
}

try {
const result = await prover.queryWithProof(
qTypes.toString(qtype),
decodedName
);
if (!result) {
return emptyRRSet;
}
const ret = Array.prototype
.concat(result.proofs, [result.answer])
.map(entry => ({
rrset: entry.toWire(),
sig: entry.signature.data.signature,
}));
return [ret];
} catch (error) {
if (trackEvent) {
trackEvent(
'error',
{
props: { name: decodedName, message: serializeError(error) },
},
true
);
}

return emptyRRSet;
}
},
},
]);
Expand Down
13 changes: 13 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function serializeError(error: any) {
if (error instanceof Error) {
const errorObject = {
...(error.message && {
message: JSON.stringify(error.message),
}),
...(error.stack && { stack: error.stack }),
};
return JSON.stringify(errorObject);
} else {
return JSON.stringify(error);
}
}
60 changes: 55 additions & 5 deletions src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,67 @@
import {
Request as CFWRequest,
ExecutionContext,
} from '@cloudflare/workers-types';
import { Server } from '@ensdomains/ccip-read-cf-worker';
import { Tracker } from '@ensdomains/server-analytics';
import { dohQuery } from '@ensdomains/dnsprovejs';
import { makeApp } from './app';

const routeHandler = (env: any) => {
interface ENV {
DOH_GATEWAY_URL: string;
PLAUSIBLE_BASE_URL: string;
}

const tracker = new Tracker('ccip-read-dns-worker.ens-cf.workers.dev', {
enableLogging: true,
});

const routeHandler = (env: ENV, trackEvent?: Function) => {
const { DOH_GATEWAY_URL } = env;
const app = makeApp(dohQuery(DOH_GATEWAY_URL as string), '/', Server);
const app = makeApp(
dohQuery(DOH_GATEWAY_URL as string),
'/',
Server,
trackEvent
);
console.log(`Serving with DoH Resolver ${DOH_GATEWAY_URL}`);
return app;
};

const logResult = async (request: CFWRequest, result: Response) => {
if (!result.body) {
return result;
}
const [streamForLog, streamForResult] = result.body.tee();
try {
const resultForLog: { data: string } = await new Response(
streamForLog
).json();

await tracker.trackEvent(
request,
'result',
{ props: { result: resultForLog.data.substring(0, 200) } },
true
);
} catch (error) {
console.log('error logging result:', error);
}
return new Response(streamForResult, result);
};

module.exports = {
fetch: async function(request: Request, env: any, _context: any) {
const router = routeHandler(env);
return await router.handle(request);
fetch: async function(
request: CFWRequest,
env: ENV,
_context: ExecutionContext
) {
if (env.PLAUSIBLE_BASE_URL) {
tracker.apiEndpoint = env.PLAUSIBLE_BASE_URL;
}
await tracker.trackEvent(request, 'request', {}, true);
await tracker.trackPageview(request, {}, true);
const router = routeHandler(env, tracker.trackEvent.bind(tracker, request));
return router.handle(request).then(logResult.bind(this, request));
},
};
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"compilerOptions": {
"module": "esnext",
"lib": ["dom", "esnext"],
"types": ["jest", "@cloudflare/workers-types"],
"importHelpers": true,
// output .d.ts declaration files for consumers
"declaration": true,
Expand Down
Loading
Loading