feat: add number library routing and cdr location support
This commit is contained in:
@@ -24,6 +24,11 @@ export interface ConfigManifest {
|
||||
policyCount: number;
|
||||
vendorGatewayCount: number;
|
||||
lineGroupCount: number;
|
||||
cityCount: number;
|
||||
phoneSegmentCount: number;
|
||||
areaCodeCount: number;
|
||||
carrierPrefixRuleCount: number;
|
||||
blockedRegionCount: number;
|
||||
checksum: string;
|
||||
}
|
||||
|
||||
@@ -74,6 +79,13 @@ type ConfigSnapshot = {
|
||||
forbiddenPeriods: Array<{ weekdayMask: number; startTime: string; endTime: string }>;
|
||||
codecs: Array<{ codec: string; priority: number }>;
|
||||
prefixRules: Array<{ direction: string; matchPrefix: string; replacePrefix: string; priority: number }>;
|
||||
blockedRegions: Array<{
|
||||
regionScope: string;
|
||||
provinceCode: string | null;
|
||||
provinceName: string | null;
|
||||
cityCode: string | null;
|
||||
cityName: string | null;
|
||||
}>;
|
||||
}>;
|
||||
lineGroups: Array<{
|
||||
id: string;
|
||||
@@ -88,12 +100,43 @@ type ConfigSnapshot = {
|
||||
status: string;
|
||||
}>;
|
||||
}>;
|
||||
cities: Array<{
|
||||
code: string;
|
||||
provinceCode: string;
|
||||
provinceName: string;
|
||||
cityCode: string;
|
||||
cityName: string;
|
||||
cityLevel: string;
|
||||
status: string;
|
||||
}>;
|
||||
phoneSegments: Array<{
|
||||
segment7: string;
|
||||
cityCode: string;
|
||||
provinceCode: string;
|
||||
provinceName: string;
|
||||
cityName: string;
|
||||
carrier: string;
|
||||
numberType: 'MOBILE';
|
||||
}>;
|
||||
areaCodes: Array<{
|
||||
areaCode: string;
|
||||
cityCode: string;
|
||||
provinceCode: string;
|
||||
provinceName: string;
|
||||
cityName: string;
|
||||
numberType: 'LANDLINE';
|
||||
}>;
|
||||
carrierPrefixRules: Array<{
|
||||
prefix: string;
|
||||
carrier: string;
|
||||
priority: number;
|
||||
}>;
|
||||
};
|
||||
|
||||
export async function publishPendingConfig(prisma: PrismaClient, redis: RedisClient, now = new Date()): Promise<PublishConfigResult> {
|
||||
const pending = await prisma.outboxEvent.findMany({
|
||||
where: {
|
||||
aggregateType: { in: ['customer_gateway_config', 'vendor_gateway_config', 'line_group_config'] },
|
||||
aggregateType: { in: ['customer_gateway_config', 'vendor_gateway_config', 'line_group_config', 'number_library_config'] },
|
||||
status: 'PENDING',
|
||||
availableAt: { lte: now }
|
||||
},
|
||||
@@ -174,7 +217,7 @@ export async function rollbackActiveConfig(redis: RedisClient): Promise<{ rolled
|
||||
}
|
||||
|
||||
async function loadSnapshot(prisma: PrismaClient): Promise<ConfigSnapshot> {
|
||||
const [customers, gateways, policies, vendorGateways, lineGroups] = await prisma.$transaction([
|
||||
const [customers, gateways, policies, vendorGateways, lineGroups, cities, phoneSegments, areaCodes, carrierPrefixRules] = await prisma.$transaction([
|
||||
prisma.customer.findMany({
|
||||
where: { deletedAt: null },
|
||||
orderBy: [{ id: 'asc' }]
|
||||
@@ -193,7 +236,8 @@ async function loadSnapshot(prisma: PrismaClient): Promise<ConfigSnapshot> {
|
||||
include: {
|
||||
forbiddenPeriods: { orderBy: [{ weekdayMask: 'asc' }, { startTime: 'asc' }] },
|
||||
codecs: { orderBy: [{ priority: 'asc' }] },
|
||||
prefixRules: { orderBy: [{ direction: 'asc' }, { priority: 'asc' }] }
|
||||
prefixRules: { orderBy: [{ direction: 'asc' }, { priority: 'asc' }] },
|
||||
blockedRegions: { orderBy: [{ regionScope: 'asc' }, { provinceCode: 'asc' }, { cityCode: 'asc' }] }
|
||||
}
|
||||
}),
|
||||
prisma.landingLineGroup.findMany({
|
||||
@@ -202,6 +246,24 @@ async function loadSnapshot(prisma: PrismaClient): Promise<ConfigSnapshot> {
|
||||
include: {
|
||||
items: { orderBy: [{ priority: 'asc' }] }
|
||||
}
|
||||
}),
|
||||
prisma.geoCity.findMany({
|
||||
where: { deletedAt: null, status: 'ENABLED' },
|
||||
orderBy: [{ provinceCode: 'asc' }, { cityCode: 'asc' }]
|
||||
}),
|
||||
prisma.phoneNumberSegment.findMany({
|
||||
where: { deletedAt: null },
|
||||
orderBy: [{ segment7: 'asc' }],
|
||||
include: { city: { select: { provinceCode: true } } }
|
||||
}),
|
||||
prisma.phoneAreaCode.findMany({
|
||||
where: { deletedAt: null },
|
||||
orderBy: [{ areaCode: 'asc' }],
|
||||
include: { city: { select: { provinceCode: true } } }
|
||||
}),
|
||||
prisma.carrierPrefixRule.findMany({
|
||||
where: { deletedAt: null },
|
||||
orderBy: [{ prefix: 'desc' }, { priority: 'asc' }]
|
||||
})
|
||||
]);
|
||||
|
||||
@@ -263,6 +325,13 @@ async function loadSnapshot(prisma: PrismaClient): Promise<ConfigSnapshot> {
|
||||
matchPrefix: rule.matchPrefix,
|
||||
replacePrefix: rule.replacePrefix,
|
||||
priority: rule.priority
|
||||
})),
|
||||
blockedRegions: gateway.blockedRegions.map((region) => ({
|
||||
regionScope: region.regionScope,
|
||||
provinceCode: region.provinceCode,
|
||||
provinceName: region.provinceName,
|
||||
cityCode: region.cityCode,
|
||||
cityName: region.cityName
|
||||
}))
|
||||
})),
|
||||
lineGroups: lineGroups.map((group) => ({
|
||||
@@ -277,6 +346,37 @@ async function loadSnapshot(prisma: PrismaClient): Promise<ConfigSnapshot> {
|
||||
concurrencyCap: item.concurrencyCap,
|
||||
status: item.status
|
||||
}))
|
||||
})),
|
||||
cities: cities.map((city) => ({
|
||||
code: city.code,
|
||||
provinceCode: city.provinceCode,
|
||||
provinceName: city.provinceName,
|
||||
cityCode: city.cityCode,
|
||||
cityName: city.cityName,
|
||||
cityLevel: city.cityLevel,
|
||||
status: city.status
|
||||
})),
|
||||
phoneSegments: phoneSegments.map((segment) => ({
|
||||
segment7: segment.segment7,
|
||||
cityCode: segment.cityCode,
|
||||
provinceCode: segment.city.provinceCode,
|
||||
provinceName: segment.provinceName,
|
||||
cityName: segment.cityName,
|
||||
carrier: segment.carrier,
|
||||
numberType: 'MOBILE'
|
||||
})),
|
||||
areaCodes: areaCodes.map((areaCode) => ({
|
||||
areaCode: areaCode.areaCode,
|
||||
cityCode: areaCode.cityCode,
|
||||
provinceCode: areaCode.city.provinceCode,
|
||||
provinceName: areaCode.provinceName,
|
||||
cityName: areaCode.cityName,
|
||||
numberType: 'LANDLINE'
|
||||
})),
|
||||
carrierPrefixRules: carrierPrefixRules.map((rule) => ({
|
||||
prefix: rule.prefix,
|
||||
carrier: rule.carrier,
|
||||
priority: rule.priority
|
||||
}))
|
||||
};
|
||||
}
|
||||
@@ -298,6 +398,11 @@ async function writeSnapshot(
|
||||
policyCount: snapshot.policies.length,
|
||||
vendorGatewayCount: snapshot.vendorGateways.length,
|
||||
lineGroupCount: snapshot.lineGroups.length,
|
||||
cityCount: snapshot.cities.length,
|
||||
phoneSegmentCount: snapshot.phoneSegments.length,
|
||||
areaCodeCount: snapshot.areaCodes.length,
|
||||
carrierPrefixRuleCount: snapshot.carrierPrefixRules.length,
|
||||
blockedRegionCount: snapshot.vendorGateways.reduce((sum, gateway) => sum + gateway.blockedRegions.length, 0),
|
||||
checksum
|
||||
};
|
||||
|
||||
@@ -321,6 +426,14 @@ async function writeSnapshot(
|
||||
}
|
||||
for (const gateway of snapshot.vendorGateways) {
|
||||
multi.set(`${prefix}:vendor_gateway:${gateway.id}`, JSON.stringify(gateway));
|
||||
for (const region of gateway.blockedRegions) {
|
||||
if (region.regionScope === 'CITY' && region.cityCode) {
|
||||
multi.sadd(`${prefix}:vendor_gateway:${gateway.id}:blocked_city_codes`, region.cityCode);
|
||||
}
|
||||
if (region.regionScope === 'PROVINCE' && region.provinceCode) {
|
||||
multi.sadd(`${prefix}:vendor_gateway:${gateway.id}:blocked_province_codes`, region.provinceCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const lineGroup of snapshot.lineGroups) {
|
||||
multi.set(`${prefix}:line_group:${lineGroup.id}`, JSON.stringify(lineGroup));
|
||||
@@ -328,6 +441,18 @@ async function writeSnapshot(
|
||||
multi.rpush(`${prefix}:line_group:${lineGroup.id}:items`, JSON.stringify(item));
|
||||
}
|
||||
}
|
||||
for (const city of snapshot.cities) {
|
||||
multi.set(`${prefix}:geo_city:${city.cityCode}`, JSON.stringify(city));
|
||||
}
|
||||
for (const segment of snapshot.phoneSegments) {
|
||||
multi.set(`${prefix}:phone_segment:${segment.segment7}`, JSON.stringify(segment));
|
||||
}
|
||||
for (const areaCode of snapshot.areaCodes) {
|
||||
multi.set(`${prefix}:area_code:${areaCode.areaCode}`, JSON.stringify(areaCode));
|
||||
}
|
||||
for (const rule of snapshot.carrierPrefixRules) {
|
||||
multi.set(`${prefix}:carrier_prefix:${rule.prefix}`, JSON.stringify(rule));
|
||||
}
|
||||
|
||||
if (previousVersion) {
|
||||
multi.set(CONFIG_PREVIOUS_VERSION_KEY, previousVersion);
|
||||
|
||||
Reference in New Issue
Block a user