@push.rocks/smartproxy
Version:
A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.
115 lines • 9.67 kB
JavaScript
import { DomainMatcher, PathMatcher, IpMatcher, HeaderMatcher } from './matchers/index.js';
/**
* Unified route specificity calculator
* Provides consistent specificity scoring across all routing components
*/
export class RouteSpecificity {
/**
* Calculate the total specificity score for a route
* Higher scores indicate more specific routes that should match first
*/
static calculate(route) {
const specificity = {
pathSpecificity: 0,
domainSpecificity: 0,
ipSpecificity: 0,
headerSpecificity: 0,
tlsSpecificity: 0,
totalScore: 0
};
// Path specificity
if (route.match.path) {
specificity.pathSpecificity = PathMatcher.calculateSpecificity(route.match.path);
}
// Domain specificity
if (route.match.domains) {
const domains = Array.isArray(route.match.domains)
? route.match.domains
: [route.match.domains];
// Use the highest specificity among all domains
specificity.domainSpecificity = Math.max(...domains.map(d => DomainMatcher.calculateSpecificity(d)));
}
// IP specificity (clientIp is an array of IPs)
if (route.match.clientIp && route.match.clientIp.length > 0) {
// Use the first IP pattern for specificity calculation
specificity.ipSpecificity = IpMatcher.calculateSpecificity(route.match.clientIp[0]);
}
// Header specificity (convert RegExp values to strings)
if (route.match.headers) {
const stringHeaders = {};
for (const [key, value] of Object.entries(route.match.headers)) {
stringHeaders[key] = value instanceof RegExp ? value.source : value;
}
specificity.headerSpecificity = HeaderMatcher.calculateSpecificity(stringHeaders);
}
// TLS version specificity
if (route.match.tlsVersion && route.match.tlsVersion.length > 0) {
specificity.tlsSpecificity = route.match.tlsVersion.length * 10;
}
// Calculate total score with weights
specificity.totalScore =
specificity.pathSpecificity * 3 + // Path is most important
specificity.domainSpecificity * 2 + // Domain is second
specificity.ipSpecificity * 1.5 + // IP is moderately important
specificity.headerSpecificity * 1 + // Headers are less important
specificity.tlsSpecificity * 0.5; // TLS is least important
return specificity;
}
/**
* Compare two routes and determine which is more specific
* @returns positive if route1 is more specific, negative if route2 is more specific, 0 if equal
*/
static compare(route1, route2) {
const spec1 = this.calculate(route1);
const spec2 = this.calculate(route2);
// First compare by total score
if (spec1.totalScore !== spec2.totalScore) {
return spec1.totalScore - spec2.totalScore;
}
// If total scores are equal, compare by individual components
// Path is most important tiebreaker
if (spec1.pathSpecificity !== spec2.pathSpecificity) {
return spec1.pathSpecificity - spec2.pathSpecificity;
}
// Then domain
if (spec1.domainSpecificity !== spec2.domainSpecificity) {
return spec1.domainSpecificity - spec2.domainSpecificity;
}
// Then IP
if (spec1.ipSpecificity !== spec2.ipSpecificity) {
return spec1.ipSpecificity - spec2.ipSpecificity;
}
// Then headers
if (spec1.headerSpecificity !== spec2.headerSpecificity) {
return spec1.headerSpecificity - spec2.headerSpecificity;
}
// Finally TLS
return spec1.tlsSpecificity - spec2.tlsSpecificity;
}
/**
* Sort routes by specificity (most specific first)
*/
static sort(routes) {
return [...routes].sort((a, b) => this.compare(b, a));
}
/**
* Find the most specific route from a list
*/
static findMostSpecific(routes) {
if (routes.length === 0)
return null;
return routes.reduce((most, current) => this.compare(current, most) > 0 ? current : most);
}
/**
* Check if a route has any matching criteria
*/
static hasMatchCriteria(route) {
const match = route.match;
return !!(match.domains ||
match.path ||
match.clientIp?.length ||
match.headers ||
match.tlsVersion?.length);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlY2lmaWNpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvc3BlY2lmaWNpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTNGOzs7R0FHRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDM0I7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFtQjtRQUNsQyxNQUFNLFdBQVcsR0FBc0I7WUFDckMsZUFBZSxFQUFFLENBQUM7WUFDbEIsaUJBQWlCLEVBQUUsQ0FBQztZQUNwQixhQUFhLEVBQUUsQ0FBQztZQUNoQixpQkFBaUIsRUFBRSxDQUFDO1lBQ3BCLGNBQWMsRUFBRSxDQUFDO1lBQ2pCLFVBQVUsRUFBRSxDQUFDO1NBQ2QsQ0FBQztRQUVGLG1CQUFtQjtRQUNuQixJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckIsV0FBVyxDQUFDLGVBQWUsR0FBRyxXQUFXLENBQUMsb0JBQW9CLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuRixDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN4QixNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO2dCQUNoRCxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPO2dCQUNyQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRTFCLGdEQUFnRDtZQUNoRCxXQUFXLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDdEMsR0FBRyxPQUFPLENBQUMs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