stable: finalized GIS aesthetics and Syria/Jordan routing synchronization
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
export declare class ExternalTelemetryService {
|
||||
private configService;
|
||||
private readonly logger;
|
||||
private readonly baseUrl;
|
||||
private readonly apiKey;
|
||||
constructor(configService: ConfigService);
|
||||
fetchCarTracks(days?: number): Promise<any[]>;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var ExternalTelemetryService_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ExternalTelemetryService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
let ExternalTelemetryService = ExternalTelemetryService_1 = class ExternalTelemetryService {
|
||||
configService;
|
||||
logger = new common_1.Logger(ExternalTelemetryService_1.name);
|
||||
baseUrl;
|
||||
apiKey;
|
||||
constructor(configService) {
|
||||
this.configService = configService;
|
||||
this.baseUrl = this.configService.get('LOCATION_SERVER_URL', '');
|
||||
this.apiKey = this.configService.get('LOCATION_SERVER_API_KEY', '');
|
||||
}
|
||||
async fetchCarTracks(days = 1) {
|
||||
if (!this.baseUrl || !this.apiKey) {
|
||||
this.logger.error('LOCATION_SERVER_URL or API_KEY not configured in .env');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
this.logger.log(`📡 Fetching car tracks from ${this.baseUrl} (Scanning: ${days} days)`);
|
||||
const response = await axios_1.default.get(`${this.baseUrl}/intaleq/ride/location/getDrirversLocationsTrack.php`, {
|
||||
params: { days },
|
||||
headers: {
|
||||
'X-API-KEY': this.apiKey,
|
||||
},
|
||||
timeout: 30000,
|
||||
});
|
||||
if (response.data && response.data.success && Array.isArray(response.data.data)) {
|
||||
this.logger.log(`✅ Successfully fetched ${response.data.data.length} telemetry points.`);
|
||||
return response.data.data;
|
||||
}
|
||||
else {
|
||||
this.logger.warn('⚠️ Received invalid data structure from location server.');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (error.response) {
|
||||
this.logger.error(`❌ Failed to fetch car tracks. Server returned Status ${error.response.status}: ${JSON.stringify(error.response.data)}`);
|
||||
}
|
||||
else {
|
||||
this.logger.error(`❌ Failed to fetch car tracks: ${error.message}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.ExternalTelemetryService = ExternalTelemetryService;
|
||||
exports.ExternalTelemetryService = ExternalTelemetryService = ExternalTelemetryService_1 = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [config_1.ConfigService])
|
||||
], ExternalTelemetryService);
|
||||
//# sourceMappingURL=external-telemetry.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"external-telemetry.service.js","sourceRoot":"","sources":["../../src/telemetry/external-telemetry.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAC/C,kDAA0B;AASnB,IAAM,wBAAwB,gCAA9B,MAAM,wBAAwB;IAKf;IAJH,MAAM,GAAG,IAAI,eAAM,CAAC,0BAAwB,CAAC,IAAI,CAAC,CAAC;IACnD,OAAO,CAAS;IAChB,MAAM,CAAS;IAEhC,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,qBAAqB,EAAE,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,yBAAyB,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC;IAMD,KAAK,CAAC,cAAc,CAAC,OAAe,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;YAC3E,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,OAAO,eAAe,IAAI,QAAQ,CAAC,CAAC;YAExF,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,sDAAsD,EAAE;gBACtG,MAAM,EAAE,EAAE,IAAI,EAAE;gBAChB,OAAO,EAAE;oBACP,WAAW,EAAE,IAAI,CAAC,MAAM;iBACzB;gBACD,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0BAA0B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,oBAAoB,CAAC,CAAC;gBACzF,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;gBAC7E,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wDAAwD,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7I,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACtE,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF,CAAA;AA/CY,4DAAwB;mCAAxB,wBAAwB;IADpC,IAAA,mBAAU,GAAE;qCAMwB,sBAAa;GALrC,wBAAwB,CA+CpC"}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { TelemetryAnalyzerService } from './telemetry-analyzer.service';
|
||||
export declare class MapRefinementController {
|
||||
private readonly analyzerService;
|
||||
constructor(analyzerService: TelemetryAnalyzerService);
|
||||
getSummary(): Promise<{
|
||||
telemetry: {
|
||||
totalPoints: number;
|
||||
last24h: number;
|
||||
activeDrivers24h: number;
|
||||
};
|
||||
roadSegments: {
|
||||
analyzed: number;
|
||||
};
|
||||
candidateRoads: {
|
||||
total: number;
|
||||
pending: number;
|
||||
approved: number;
|
||||
rejected: number;
|
||||
};
|
||||
}>;
|
||||
syncExternal(): Promise<{
|
||||
imported: number;
|
||||
}>;
|
||||
refreshCache(): Promise<{
|
||||
cachedCount: number;
|
||||
}>;
|
||||
analyzeRoadSpeeds(hours?: number): Promise<{
|
||||
segmentsUpdated: number;
|
||||
totalPointsProcessed: number;
|
||||
topAdjustments: any[];
|
||||
}>;
|
||||
discoverNewRoads(hours?: number): Promise<{
|
||||
candidatesFound: number;
|
||||
candidates: any[];
|
||||
}>;
|
||||
getCongestionData(north: number, south: number, east: number, west: number): Promise<any[]>;
|
||||
approveCandidate(id: string): Promise<{
|
||||
message: string;
|
||||
status: string;
|
||||
}>;
|
||||
rejectCandidate(id: string): Promise<{
|
||||
message: string;
|
||||
status: string;
|
||||
}>;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MapRefinementController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const telemetry_analyzer_service_1 = require("./telemetry-analyzer.service");
|
||||
let MapRefinementController = class MapRefinementController {
|
||||
analyzerService;
|
||||
constructor(analyzerService) {
|
||||
this.analyzerService = analyzerService;
|
||||
}
|
||||
async getSummary() {
|
||||
return this.analyzerService.getAnalysisSummary();
|
||||
}
|
||||
async syncExternal() {
|
||||
return this.analyzerService.syncExternalData();
|
||||
}
|
||||
async refreshCache() {
|
||||
return this.analyzerService.refreshTrafficCache();
|
||||
}
|
||||
async analyzeRoadSpeeds(hours) {
|
||||
const sinceHours = hours ? Number(hours) : 24;
|
||||
return this.analyzerService.analyzeRoadSpeeds(sinceHours);
|
||||
}
|
||||
async discoverNewRoads(hours) {
|
||||
const sinceHours = hours ? Number(hours) : 168;
|
||||
return this.analyzerService.discoverNewRoads(sinceHours);
|
||||
}
|
||||
async getCongestionData(north, south, east, west) {
|
||||
if (!north || !south || !east || !west) {
|
||||
throw new common_1.HttpException('Bounds required: north, south, east, west / يجب تحديد الحدود الجغرافية', common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
return this.analyzerService.getCongestionData({
|
||||
north: Number(north),
|
||||
south: Number(south),
|
||||
east: Number(east),
|
||||
west: Number(west),
|
||||
});
|
||||
}
|
||||
async approveCandidate(id) {
|
||||
return { message: `Candidate ${id} approved`, status: 'approved' };
|
||||
}
|
||||
async rejectCandidate(id) {
|
||||
return { message: `Candidate ${id} rejected`, status: 'rejected' };
|
||||
}
|
||||
};
|
||||
exports.MapRefinementController = MapRefinementController;
|
||||
__decorate([
|
||||
(0, common_1.Get)('summary'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Get analysis summary 📊 / ملخص التحليل' }),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "getSummary", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('sync-external'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Sync telemetry from external server 📡 / مزامنة البيانات الخارجية' }),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "syncExternal", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('refresh-cache'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Refresh Redis traffic snapshot 🚀 / تحديث ذاكرة التخزين' }),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "refreshCache", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('analyze-speeds'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Run road speed analysis 🚗 / تشغيل تحليل سرعات الطرق' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'hours', required: false, description: 'Hours to look back (default: 24)' }),
|
||||
__param(0, (0, common_1.Query)('hours')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "analyzeRoadSpeeds", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('discover-roads'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Discover new roads from telemetry 🛣️ / اكتشاف طرق جديدة' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'hours', required: false, description: 'Hours to look back (default: 168 = 1 week)' }),
|
||||
__param(0, (0, common_1.Query)('hours')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "discoverNewRoads", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('congestion'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Get congestion data for heatmap 🗺️ / بيانات الازدحام' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'north', required: true }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'south', required: true }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'east', required: true }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'west', required: true }),
|
||||
__param(0, (0, common_1.Query)('north')),
|
||||
__param(1, (0, common_1.Query)('south')),
|
||||
__param(2, (0, common_1.Query)('east')),
|
||||
__param(3, (0, common_1.Query)('west')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number, Number, Number, Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "getCongestionData", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)('candidates/:id/approve'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Approve a candidate road ✅ / الموافقة على طريق مرشح' }),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "approveCandidate", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)('candidates/:id/reject'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Reject a candidate road ❌ / رفض طريق مرشح' }),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], MapRefinementController.prototype, "rejectCandidate", null);
|
||||
exports.MapRefinementController = MapRefinementController = __decorate([
|
||||
(0, swagger_1.ApiTags)('map-refinement'),
|
||||
(0, common_1.Controller)('map-refinement'),
|
||||
__metadata("design:paramtypes", [telemetry_analyzer_service_1.TelemetryAnalyzerService])
|
||||
], MapRefinementController);
|
||||
//# sourceMappingURL=map-refinement.controller.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"map-refinement.controller.js","sourceRoot":"","sources":["../../src/telemetry/map-refinement.controller.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { TelemetryLog } from './telemetry.entity';
|
||||
import { RoadSegmentStat } from '../maps/road-stat.entity';
|
||||
import { CandidateRoad } from '../maps/candidate-road.entity';
|
||||
import { RedisService } from '../common/redis.service';
|
||||
import { ExternalTelemetryService } from './external-telemetry.service';
|
||||
export declare class TelemetryAnalyzerService {
|
||||
private telemetryRepo;
|
||||
private roadStatRepo;
|
||||
private candidateRoadRepo;
|
||||
private dataSource;
|
||||
private redisService;
|
||||
private externalTelemetry;
|
||||
private readonly logger;
|
||||
private readonly TRAFFIC_CACHE_KEY;
|
||||
constructor(telemetryRepo: Repository<TelemetryLog>, roadStatRepo: Repository<RoadSegmentStat>, candidateRoadRepo: Repository<CandidateRoad>, dataSource: DataSource, redisService: RedisService, externalTelemetry: ExternalTelemetryService);
|
||||
handleNightlyIntelligence(): Promise<void>;
|
||||
syncExternalData(days?: number): Promise<{
|
||||
imported: number;
|
||||
}>;
|
||||
refreshTrafficCache(): Promise<{
|
||||
cachedCount: number;
|
||||
}>;
|
||||
analyzeRoadSpeeds(sinceHours?: number): Promise<{
|
||||
segmentsUpdated: number;
|
||||
totalPointsProcessed: number;
|
||||
topAdjustments: any[];
|
||||
}>;
|
||||
discoverNewRoads(sinceHours?: number): Promise<{
|
||||
candidatesFound: number;
|
||||
candidates: any[];
|
||||
}>;
|
||||
getCongestionData(bounds: {
|
||||
north: number;
|
||||
south: number;
|
||||
east: number;
|
||||
west: number;
|
||||
}): Promise<any[]>;
|
||||
getAnalysisSummary(): Promise<{
|
||||
telemetry: {
|
||||
totalPoints: number;
|
||||
last24h: number;
|
||||
activeDrivers24h: number;
|
||||
};
|
||||
roadSegments: {
|
||||
analyzed: number;
|
||||
};
|
||||
candidateRoads: {
|
||||
total: number;
|
||||
pending: number;
|
||||
approved: number;
|
||||
rejected: number;
|
||||
};
|
||||
}>;
|
||||
private calculateConfidence;
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var TelemetryAnalyzerService_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelemetryAnalyzerService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const schedule_1 = require("@nestjs/schedule");
|
||||
const telemetry_entity_1 = require("./telemetry.entity");
|
||||
const road_stat_entity_1 = require("../maps/road-stat.entity");
|
||||
const candidate_road_entity_1 = require("../maps/candidate-road.entity");
|
||||
const redis_service_1 = require("../common/redis.service");
|
||||
const external_telemetry_service_1 = require("./external-telemetry.service");
|
||||
let TelemetryAnalyzerService = TelemetryAnalyzerService_1 = class TelemetryAnalyzerService {
|
||||
telemetryRepo;
|
||||
roadStatRepo;
|
||||
candidateRoadRepo;
|
||||
dataSource;
|
||||
redisService;
|
||||
externalTelemetry;
|
||||
logger = new common_1.Logger(TelemetryAnalyzerService_1.name);
|
||||
TRAFFIC_CACHE_KEY = 'traffic_snapshot';
|
||||
constructor(telemetryRepo, roadStatRepo, candidateRoadRepo, dataSource, redisService, externalTelemetry) {
|
||||
this.telemetryRepo = telemetryRepo;
|
||||
this.roadStatRepo = roadStatRepo;
|
||||
this.candidateRoadRepo = candidateRoadRepo;
|
||||
this.dataSource = dataSource;
|
||||
this.redisService = redisService;
|
||||
this.externalTelemetry = externalTelemetry;
|
||||
}
|
||||
async handleNightlyIntelligence() {
|
||||
this.logger.log('⏰ Starting automated 3 AM intelligence process...');
|
||||
try {
|
||||
await this.syncExternalData(1);
|
||||
await this.analyzeRoadSpeeds(24);
|
||||
await this.discoverNewRoads(168);
|
||||
await this.refreshTrafficCache();
|
||||
this.logger.log('✅ 3 AM intelligence process complete.');
|
||||
}
|
||||
catch (error) {
|
||||
this.logger.error('❌ Nightly intelligence failed:', error.stack);
|
||||
}
|
||||
}
|
||||
async syncExternalData(days = 1) {
|
||||
this.logger.log(`📡 Starting batch sync (Window: ${days} days)...`);
|
||||
const tracks = await this.externalTelemetry.fetchCarTracks(days);
|
||||
if (!tracks || tracks.length === 0) {
|
||||
this.logger.warn(`⚠️ No tracks found on external server for the last ${days} days.`);
|
||||
return { imported: 0 };
|
||||
}
|
||||
this.logger.log(`✅ Received ${tracks.length} tracks. Commencing batch insertion...`);
|
||||
this.logger.log(`📥 Saving ${tracks.length} points to database...`);
|
||||
const entities = tracks.map(t => ({
|
||||
driverId: t.driver_id,
|
||||
latitude: t.latitude,
|
||||
longitude: t.longitude,
|
||||
speed: t.speed,
|
||||
heading: t.heading,
|
||||
timestamp: new Date(t.created_at || t.timestamp),
|
||||
location: {
|
||||
type: 'Point',
|
||||
coordinates: [t.longitude, t.latitude],
|
||||
},
|
||||
}));
|
||||
const CHUNK_SIZE = 1000;
|
||||
for (let i = 0; i < entities.length; i += CHUNK_SIZE) {
|
||||
const chunk = entities.slice(i, i + CHUNK_SIZE);
|
||||
const logs = this.telemetryRepo.create(chunk);
|
||||
await this.telemetryRepo.save(logs);
|
||||
}
|
||||
return { imported: tracks.length };
|
||||
}
|
||||
async refreshTrafficCache() {
|
||||
this.logger.log('🚀 Refreshing Redis traffic snapshot...');
|
||||
const congested = await this.roadStatRepo.query(`
|
||||
SELECT
|
||||
"segmentId",
|
||||
"congestionFactor",
|
||||
ST_AsGeoJSON(geometry) as geojson
|
||||
FROM road_segment_stats
|
||||
WHERE "congestionFactor" > 1.1
|
||||
`);
|
||||
if (congested.length === 0) {
|
||||
await this.redisService.del(this.TRAFFIC_CACHE_KEY);
|
||||
return { cachedCount: 0 };
|
||||
}
|
||||
await this.redisService.set(this.TRAFFIC_CACHE_KEY, congested);
|
||||
this.logger.log(`✅ Cached ${congested.length} congested segments in Redis.`);
|
||||
return { cachedCount: congested.length };
|
||||
}
|
||||
async analyzeRoadSpeeds(sinceHours = 24) {
|
||||
this.logger.log(`🔍 Starting road speed analysis for last ${sinceHours}h...`);
|
||||
const matchedData = await this.dataSource.query(`
|
||||
WITH matched_points AS (
|
||||
SELECT
|
||||
t.id AS telemetry_id,
|
||||
t.speed,
|
||||
t."driverId",
|
||||
l.osm_id,
|
||||
l.name,
|
||||
l.highway,
|
||||
l.way_4326,
|
||||
ST_Distance(t.location::geography, l.way_4326::geography) AS distance_m
|
||||
FROM telemetry_logs t
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT osm_id, name, highway, ST_Transform(way, 4326) AS way_4326
|
||||
FROM planet_osm_line
|
||||
WHERE highway IS NOT NULL
|
||||
ORDER BY way <-> ST_Transform(t.location::geometry, 3857)
|
||||
LIMIT 1
|
||||
) l
|
||||
WHERE t.timestamp >= NOW() - INTERVAL '${sinceHours} hours'
|
||||
AND t.speed > 2 -- Ignore stationary points / تجاهل النقاط الثابتة
|
||||
AND ST_Distance(t.location::geography, l.way_4326::geography) < 15 -- 15m snap threshold
|
||||
)
|
||||
SELECT
|
||||
osm_id::text AS segment_id,
|
||||
name,
|
||||
highway,
|
||||
AVG(speed) AS avg_speed,
|
||||
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY speed) AS median_speed,
|
||||
COUNT(*) AS sample_count,
|
||||
COUNT(DISTINCT "driverId") AS unique_drivers,
|
||||
ST_AsGeoJSON(MIN(way_4326)) AS geojson
|
||||
FROM matched_points
|
||||
GROUP BY osm_id, name, highway
|
||||
HAVING COUNT(*) >= 3 -- Minimum 3 samples for reliability / 3 عينات على الأقل
|
||||
ORDER BY sample_count DESC
|
||||
`);
|
||||
let segmentsUpdated = 0;
|
||||
let totalPoints = 0;
|
||||
for (const row of matchedData) {
|
||||
const medianSpeed = parseFloat(row.median_speed);
|
||||
const sampleCount = parseInt(row.sample_count);
|
||||
const geojson = JSON.parse(row.geojson);
|
||||
totalPoints += sampleCount;
|
||||
let congestionFactor = 1.0;
|
||||
const majorRoadTypes = ['primary', 'secondary', 'trunk', 'motorway'];
|
||||
if (majorRoadTypes.includes(row.highway) && medianSpeed < 30) {
|
||||
congestionFactor = 30 / Math.max(medianSpeed, 1);
|
||||
}
|
||||
await this.roadStatRepo.upsert({
|
||||
segmentId: row.segment_id,
|
||||
averageSpeed: medianSpeed,
|
||||
congestionFactor,
|
||||
sampleCount,
|
||||
lastUpdated: new Date(),
|
||||
geometry: geojson,
|
||||
}, ['segmentId']);
|
||||
segmentsUpdated++;
|
||||
}
|
||||
return {
|
||||
segmentsUpdated,
|
||||
totalPointsProcessed: totalPoints,
|
||||
topAdjustments: matchedData.slice(0, 10).map(d => ({
|
||||
segmentId: d.segment_id,
|
||||
name: d.name || 'Unnamed Road',
|
||||
speed: Math.round(parseFloat(d.median_speed)),
|
||||
samples: parseInt(d.sample_count)
|
||||
}))
|
||||
};
|
||||
}
|
||||
async discoverNewRoads(sinceHours = 168) {
|
||||
this.logger.log(`🛣️ Starting road discovery for last ${sinceHours}h (${sinceHours / 24}d)...`);
|
||||
const candidates = await this.dataSource.query(`
|
||||
WITH off_road_points AS (
|
||||
SELECT
|
||||
t.id,
|
||||
t."driverId",
|
||||
t.speed,
|
||||
t.heading,
|
||||
t.location,
|
||||
t.timestamp
|
||||
FROM telemetry_logs t
|
||||
WHERE t.timestamp >= NOW() - INTERVAL '${sinceHours} hours'
|
||||
AND t.speed > 5 -- Moving, not parked / متحرك وليس متوقف
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM planet_osm_line l
|
||||
WHERE l.highway IS NOT NULL
|
||||
AND ST_DWithin(t.location::geography, ST_Transform(l.way, 4326)::geography, 15)
|
||||
)
|
||||
),
|
||||
-- Step 2: Cluster nearby off-road points using DBSCAN
|
||||
-- الخطوة 2: تجميع النقاط القريبة باستخدام DBSCAN
|
||||
clustered AS (
|
||||
SELECT
|
||||
*,
|
||||
ST_ClusterDBSCAN(location::geometry, eps := 0.0003, minpoints := 5)
|
||||
OVER () AS cluster_id
|
||||
FROM off_road_points
|
||||
)
|
||||
-- Step 3: Aggregate clusters into candidate road lines
|
||||
-- الخطوة 3: تحويل التجمعات إلى خطوط طرق مرشحة
|
||||
SELECT
|
||||
cluster_id,
|
||||
COUNT(*) AS total_points,
|
||||
COUNT(DISTINCT "driverId") AS unique_drivers,
|
||||
AVG(speed) AS avg_speed,
|
||||
ST_AsGeoJSON(ST_MakeLine(location::geometry ORDER BY timestamp)) AS geojson_line,
|
||||
ST_Length(ST_MakeLine(location::geometry ORDER BY timestamp)::geography) AS length_m
|
||||
FROM clustered
|
||||
WHERE cluster_id IS NOT NULL
|
||||
GROUP BY cluster_id
|
||||
HAVING COUNT(DISTINCT "driverId") >= 2 -- At least 2 drivers / سائقان على الأقل
|
||||
AND COUNT(*) >= 10 -- At least 10 points / 10 نقاط على الأقل
|
||||
ORDER BY unique_drivers DESC, total_points DESC
|
||||
`);
|
||||
const savedCandidates = [];
|
||||
for (const c of candidates) {
|
||||
const geojson = JSON.parse(c.geojson_line);
|
||||
const confidence = this.calculateConfidence(parseInt(c.unique_drivers), parseInt(c.total_points), parseFloat(c.length_m));
|
||||
const candidate = this.candidateRoadRepo.create({
|
||||
geometry: geojson,
|
||||
uniqueDriverCount: parseInt(c.unique_drivers),
|
||||
totalPoints: parseInt(c.total_points),
|
||||
averageSpeed: parseFloat(c.avg_speed),
|
||||
lengthMeters: parseFloat(c.length_m),
|
||||
confidence,
|
||||
status: 'pending',
|
||||
});
|
||||
const saved = await this.candidateRoadRepo.save(candidate);
|
||||
savedCandidates.push({
|
||||
id: saved.id,
|
||||
uniqueDrivers: saved.uniqueDriverCount,
|
||||
totalPoints: saved.totalPoints,
|
||||
averageSpeed: Math.round(saved.averageSpeed * 10) / 10,
|
||||
lengthMeters: Math.round(saved.lengthMeters),
|
||||
confidence: Math.round(saved.confidence * 100) / 100,
|
||||
geojson,
|
||||
});
|
||||
}
|
||||
this.logger.log(`✅ Road discovery complete: ${savedCandidates.length} candidates found`);
|
||||
return {
|
||||
candidatesFound: savedCandidates.length,
|
||||
candidates: savedCandidates,
|
||||
};
|
||||
}
|
||||
async getCongestionData(bounds) {
|
||||
return this.dataSource.query(`
|
||||
SELECT
|
||||
rs."segmentId" AS segment_id,
|
||||
rs."averageSpeed" AS avg_speed,
|
||||
rs."congestionFactor" AS congestion_factor,
|
||||
rs."sampleCount" AS sample_count,
|
||||
ST_AsGeoJSON(rs.geometry) AS geojson
|
||||
FROM road_segment_stats rs
|
||||
WHERE rs.geometry IS NOT NULL
|
||||
AND ST_Intersects(
|
||||
rs.geometry::geometry,
|
||||
ST_MakeEnvelope($1, $2, $3, $4, 4326)
|
||||
)
|
||||
AND rs."sampleCount" >= 3
|
||||
ORDER BY rs."congestionFactor" DESC
|
||||
`, [bounds.west, bounds.south, bounds.east, bounds.north]);
|
||||
}
|
||||
async getAnalysisSummary() {
|
||||
const [telemetryCount] = await this.dataSource.query(`SELECT COUNT(*) as count FROM telemetry_logs`);
|
||||
const [roadStatCount] = await this.dataSource.query(`SELECT COUNT(*) as count FROM road_segment_stats`);
|
||||
const [candidateCount] = await this.dataSource.query(`SELECT COUNT(*) as count,
|
||||
COUNT(*) FILTER (WHERE status = 'pending') as pending,
|
||||
COUNT(*) FILTER (WHERE status = 'approved') as approved,
|
||||
COUNT(*) FILTER (WHERE status = 'rejected') as rejected
|
||||
FROM candidate_roads`);
|
||||
const [recentActivity] = await this.dataSource.query(`
|
||||
SELECT
|
||||
COUNT(*) as points_last_24h,
|
||||
COUNT(DISTINCT "driverId") as active_drivers_24h
|
||||
FROM telemetry_logs
|
||||
WHERE timestamp >= NOW() - INTERVAL '24 hours'
|
||||
`);
|
||||
return {
|
||||
telemetry: {
|
||||
totalPoints: parseInt(telemetryCount?.count || '0'),
|
||||
last24h: parseInt(recentActivity?.points_last_24h || '0'),
|
||||
activeDrivers24h: parseInt(recentActivity?.active_drivers_24h || '0'),
|
||||
},
|
||||
roadSegments: {
|
||||
analyzed: parseInt(roadStatCount?.count || '0'),
|
||||
},
|
||||
candidateRoads: {
|
||||
total: parseInt(candidateCount?.count || '0'),
|
||||
pending: parseInt(candidateCount?.pending || '0'),
|
||||
approved: parseInt(candidateCount?.approved || '0'),
|
||||
rejected: parseInt(candidateCount?.rejected || '0'),
|
||||
},
|
||||
};
|
||||
}
|
||||
calculateConfidence(uniqueDrivers, totalPoints, lengthMeters) {
|
||||
const driverScore = Math.min(uniqueDrivers / 5, 1.0) * 0.4;
|
||||
const pointScore = Math.min(totalPoints / 50, 1.0) * 0.3;
|
||||
let lengthScore = 0;
|
||||
if (lengthMeters >= 50 && lengthMeters <= 2000) {
|
||||
lengthScore = 0.3;
|
||||
}
|
||||
else if (lengthMeters > 2000) {
|
||||
lengthScore = 0.2;
|
||||
}
|
||||
return Math.round((driverScore + pointScore + lengthScore) * 100) / 100;
|
||||
}
|
||||
};
|
||||
exports.TelemetryAnalyzerService = TelemetryAnalyzerService;
|
||||
__decorate([
|
||||
(0, schedule_1.Cron)('0 3 * * *'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryAnalyzerService.prototype, "handleNightlyIntelligence", null);
|
||||
exports.TelemetryAnalyzerService = TelemetryAnalyzerService = TelemetryAnalyzerService_1 = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(telemetry_entity_1.TelemetryLog)),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(road_stat_entity_1.RoadSegmentStat)),
|
||||
__param(2, (0, typeorm_1.InjectRepository)(candidate_road_entity_1.CandidateRoad)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.DataSource,
|
||||
redis_service_1.RedisService,
|
||||
external_telemetry_service_1.ExternalTelemetryService])
|
||||
], TelemetryAnalyzerService);
|
||||
//# sourceMappingURL=telemetry-analyzer.service.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,77 @@
|
||||
import { TelemetryService, type DriverTelemetryDto } from './telemetry.service';
|
||||
import { TelemetryAnalyzerService } from './telemetry-analyzer.service';
|
||||
export declare class TelemetryController {
|
||||
private readonly telemetryService;
|
||||
private readonly analyzerService;
|
||||
constructor(telemetryService: TelemetryService, analyzerService: TelemetryAnalyzerService);
|
||||
ingest(data: DriverTelemetryDto): Promise<{
|
||||
success: boolean;
|
||||
timestamp: Date;
|
||||
}>;
|
||||
sync(): Promise<{
|
||||
imported: number;
|
||||
}>;
|
||||
analyze(hours?: number): Promise<{
|
||||
success: boolean;
|
||||
roadAnalysis: {
|
||||
segmentsUpdated: number;
|
||||
totalPointsProcessed: number;
|
||||
topAdjustments: any[];
|
||||
};
|
||||
roadDiscovery: {
|
||||
candidatesFound: number;
|
||||
candidates: any[];
|
||||
};
|
||||
}>;
|
||||
processIntelligence(hours?: number): Promise<{
|
||||
success: boolean;
|
||||
timestamp: Date;
|
||||
sync: {
|
||||
imported: number;
|
||||
};
|
||||
analysis: {
|
||||
roads: {
|
||||
segmentsUpdated: number;
|
||||
totalPointsProcessed: number;
|
||||
topAdjustments: any[];
|
||||
};
|
||||
discovery: {
|
||||
candidatesFound: number;
|
||||
candidates: any[];
|
||||
};
|
||||
};
|
||||
currentStatus: {
|
||||
telemetry: {
|
||||
totalPoints: number;
|
||||
last24h: number;
|
||||
activeDrivers24h: number;
|
||||
};
|
||||
roadSegments: {
|
||||
analyzed: number;
|
||||
};
|
||||
candidateRoads: {
|
||||
total: number;
|
||||
pending: number;
|
||||
approved: number;
|
||||
rejected: number;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
getSummary(): Promise<{
|
||||
telemetry: {
|
||||
totalPoints: number;
|
||||
last24h: number;
|
||||
activeDrivers24h: number;
|
||||
};
|
||||
roadSegments: {
|
||||
analyzed: number;
|
||||
};
|
||||
candidateRoads: {
|
||||
total: number;
|
||||
pending: number;
|
||||
approved: number;
|
||||
rejected: number;
|
||||
};
|
||||
}>;
|
||||
getNearby(lat: number, lng: number, radius: number): Promise<import("./telemetry.entity").TelemetryLog[]>;
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelemetryController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const telemetry_service_1 = require("./telemetry.service");
|
||||
const telemetry_analyzer_service_1 = require("./telemetry-analyzer.service");
|
||||
let TelemetryController = class TelemetryController {
|
||||
telemetryService;
|
||||
analyzerService;
|
||||
constructor(telemetryService, analyzerService) {
|
||||
this.telemetryService = telemetryService;
|
||||
this.analyzerService = analyzerService;
|
||||
}
|
||||
async ingest(data) {
|
||||
return this.telemetryService.ingest(data);
|
||||
}
|
||||
async sync() {
|
||||
return this.analyzerService.syncExternalData();
|
||||
}
|
||||
async analyze(hours) {
|
||||
const roadResults = await this.analyzerService.analyzeRoadSpeeds(hours || 24);
|
||||
const discoveryResults = await this.analyzerService.discoverNewRoads(hours || 168);
|
||||
return {
|
||||
success: true,
|
||||
roadAnalysis: roadResults,
|
||||
roadDiscovery: discoveryResults,
|
||||
};
|
||||
}
|
||||
async processIntelligence(hours) {
|
||||
const syncResults = await this.analyzerService.syncExternalData();
|
||||
const roadResults = await this.analyzerService.analyzeRoadSpeeds(hours || 24);
|
||||
const discoveryResults = await this.analyzerService.discoverNewRoads(hours || 168);
|
||||
const summary = await this.analyzerService.getAnalysisSummary();
|
||||
return {
|
||||
success: true,
|
||||
timestamp: new Date(),
|
||||
sync: syncResults,
|
||||
analysis: {
|
||||
roads: roadResults,
|
||||
discovery: discoveryResults,
|
||||
},
|
||||
currentStatus: summary,
|
||||
};
|
||||
}
|
||||
async getSummary() {
|
||||
return this.analyzerService.getAnalysisSummary();
|
||||
}
|
||||
async getNearby(lat, lng, radius) {
|
||||
return this.telemetryService.getRecentDrivers(Number(lat), Number(lng), Number(radius));
|
||||
}
|
||||
};
|
||||
exports.TelemetryController = TelemetryController;
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Ingest driver telemetry 📡' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "ingest", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('sync'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Sync data from external server 📡' }),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "sync", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('analyze'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Trigger road and speed analysis 🧠' }),
|
||||
__param(0, (0, common_1.Query)('hours')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "analyze", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('process-intelligence'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Automated One-Click Sync & Analyze 🚀' }),
|
||||
__param(0, (0, common_1.Query)('hours')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "processIntelligence", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('summary'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Get analysis summary 📊' }),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "getSummary", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('nearby'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Find nearby drivers 📍' }),
|
||||
__param(0, (0, common_1.Query)('lat')),
|
||||
__param(1, (0, common_1.Query)('lng')),
|
||||
__param(2, (0, common_1.Query)('radius')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Number, Number, Number]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TelemetryController.prototype, "getNearby", null);
|
||||
exports.TelemetryController = TelemetryController = __decorate([
|
||||
(0, swagger_1.ApiTags)('telemetry'),
|
||||
(0, common_1.Controller)('telemetry'),
|
||||
__metadata("design:paramtypes", [telemetry_service_1.TelemetryService,
|
||||
telemetry_analyzer_service_1.TelemetryAnalyzerService])
|
||||
], TelemetryController);
|
||||
//# sourceMappingURL=telemetry.controller.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"telemetry.controller.js","sourceRoot":"","sources":["../../src/telemetry/telemetry.controller.ts"],"names":[],"mappings":"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"}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
export declare class TelemetryLog {
|
||||
id: number;
|
||||
driverId: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
speed: number;
|
||||
heading: number;
|
||||
timestamp: Date;
|
||||
location: any;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelemetryLog = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
let TelemetryLog = class TelemetryLog {
|
||||
id;
|
||||
driverId;
|
||||
latitude;
|
||||
longitude;
|
||||
speed;
|
||||
heading;
|
||||
timestamp;
|
||||
location;
|
||||
};
|
||||
exports.TelemetryLog = TelemetryLog;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)(),
|
||||
__metadata("design:type", Number)
|
||||
], TelemetryLog.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)(),
|
||||
(0, typeorm_1.Index)(),
|
||||
__metadata("design:type", String)
|
||||
], TelemetryLog.prototype, "driverId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)('decimal', { precision: 10, scale: 7 }),
|
||||
__metadata("design:type", Number)
|
||||
], TelemetryLog.prototype, "latitude", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)('decimal', { precision: 10, scale: 7 }),
|
||||
__metadata("design:type", Number)
|
||||
], TelemetryLog.prototype, "longitude", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)('float'),
|
||||
__metadata("design:type", Number)
|
||||
], TelemetryLog.prototype, "speed", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)('float'),
|
||||
__metadata("design:type", Number)
|
||||
], TelemetryLog.prototype, "heading", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)(),
|
||||
(0, typeorm_1.Index)(),
|
||||
__metadata("design:type", Date)
|
||||
], TelemetryLog.prototype, "timestamp", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
type: 'geography',
|
||||
spatialFeatureType: 'Point',
|
||||
srid: 4326,
|
||||
nullable: true,
|
||||
}),
|
||||
(0, typeorm_1.Index)({ spatial: true }),
|
||||
__metadata("design:type", Object)
|
||||
], TelemetryLog.prototype, "location", void 0);
|
||||
exports.TelemetryLog = TelemetryLog = __decorate([
|
||||
(0, typeorm_1.Entity)('telemetry_logs')
|
||||
], TelemetryLog);
|
||||
//# sourceMappingURL=telemetry.entity.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"telemetry.entity.js","sourceRoot":"","sources":["../../src/telemetry/telemetry.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA0F;AAGnF,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEvB,EAAE,CAAS;IAIX,QAAQ,CAAS;IAGjB,QAAQ,CAAS;IAGjB,SAAS,CAAS;IAGlB,KAAK,CAAS;IAGd,OAAO,CAAS;IAIhB,SAAS,CAAO;IAWhB,QAAQ,CAAM;CACf,CAAA;AAlCY,oCAAY;AAEvB;IADC,IAAA,gCAAsB,GAAE;;wCACd;AAIX;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,GAAE;;8CACS;AAGjB;IADC,IAAA,gBAAM,EAAC,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;8CAC9B;AAGjB;IADC,IAAA,gBAAM,EAAC,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;+CAC7B;AAGlB;IADC,IAAA,gBAAM,EAAC,OAAO,CAAC;;2CACF;AAGd;IADC,IAAA,gBAAM,EAAC,OAAO,CAAC;;6CACA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,eAAK,GAAE;8BACG,IAAI;+CAAC;AAWhB;IAPC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,OAAO;QAC3B,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,IAAI;KACf,CAAC;IACD,IAAA,eAAK,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;8CACX;uBAjCH,YAAY;IADxB,IAAA,gBAAM,EAAC,gBAAgB,CAAC;GACZ,YAAY,CAkCxB"}
|
||||
@@ -0,0 +1,2 @@
|
||||
export declare class TelemetryModule {
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelemetryModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const telemetry_entity_1 = require("./telemetry.entity");
|
||||
const telemetry_service_1 = require("./telemetry.service");
|
||||
const telemetry_controller_1 = require("./telemetry.controller");
|
||||
const telemetry_analyzer_service_1 = require("./telemetry-analyzer.service");
|
||||
const map_refinement_controller_1 = require("./map-refinement.controller");
|
||||
const road_stat_entity_1 = require("../maps/road-stat.entity");
|
||||
const candidate_road_entity_1 = require("../maps/candidate-road.entity");
|
||||
const redis_module_1 = require("../common/redis.module");
|
||||
const redis_service_1 = require("../common/redis.service");
|
||||
const external_telemetry_service_1 = require("./external-telemetry.service");
|
||||
let TelemetryModule = class TelemetryModule {
|
||||
};
|
||||
exports.TelemetryModule = TelemetryModule;
|
||||
exports.TelemetryModule = TelemetryModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
typeorm_1.TypeOrmModule.forFeature([telemetry_entity_1.TelemetryLog, road_stat_entity_1.RoadSegmentStat, candidate_road_entity_1.CandidateRoad]),
|
||||
redis_module_1.RedisModule,
|
||||
],
|
||||
controllers: [telemetry_controller_1.TelemetryController, map_refinement_controller_1.MapRefinementController],
|
||||
providers: [telemetry_service_1.TelemetryService, telemetry_analyzer_service_1.TelemetryAnalyzerService, redis_service_1.RedisService, external_telemetry_service_1.ExternalTelemetryService],
|
||||
exports: [telemetry_service_1.TelemetryService, telemetry_analyzer_service_1.TelemetryAnalyzerService, redis_service_1.RedisService, external_telemetry_service_1.ExternalTelemetryService],
|
||||
})
|
||||
], TelemetryModule);
|
||||
//# sourceMappingURL=telemetry.module.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"telemetry.module.js","sourceRoot":"","sources":["../../src/telemetry/telemetry.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,yDAAkD;AAClD,2DAAuD;AACvD,iEAA6D;AAC7D,6EAAwE;AACxE,2EAAsE;AACtE,+DAA2D;AAC3D,yEAA8D;AAC9D,yDAAqD;AACrD,2DAAuD;AAEvD,6EAAwE;AAWjE,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IAT3B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,+BAAY,EAAE,kCAAe,EAAE,qCAAa,CAAC,CAAC;YACxE,0BAAW;SACZ;QACD,WAAW,EAAE,CAAC,0CAAmB,EAAE,mDAAuB,CAAC;QAC3D,SAAS,EAAE,CAAC,oCAAgB,EAAE,qDAAwB,EAAE,4BAAY,EAAE,qDAAwB,CAAC;QAC/F,OAAO,EAAE,CAAC,oCAAgB,EAAE,qDAAwB,EAAE,4BAAY,EAAE,qDAAwB,CAAC;KAC9F,CAAC;GACW,eAAe,CAAG"}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { TelemetryLog } from './telemetry.entity';
|
||||
export interface DriverTelemetryDto {
|
||||
driver_id: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
speed: number;
|
||||
heading: number;
|
||||
}
|
||||
export declare class TelemetryService {
|
||||
private telemetryRepository;
|
||||
private readonly logger;
|
||||
constructor(telemetryRepository: Repository<TelemetryLog>);
|
||||
ingest(data: DriverTelemetryDto): Promise<{
|
||||
success: boolean;
|
||||
timestamp: Date;
|
||||
}>;
|
||||
getRecentDrivers(lat: number, lng: number, radiusMeters?: number): Promise<TelemetryLog[]>;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var TelemetryService_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelemetryService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const telemetry_entity_1 = require("./telemetry.entity");
|
||||
let TelemetryService = TelemetryService_1 = class TelemetryService {
|
||||
telemetryRepository;
|
||||
logger = new common_1.Logger(TelemetryService_1.name);
|
||||
constructor(telemetryRepository) {
|
||||
this.telemetryRepository = telemetryRepository;
|
||||
}
|
||||
async ingest(data) {
|
||||
const log = this.telemetryRepository.create({
|
||||
driverId: data.driver_id,
|
||||
latitude: data.latitude,
|
||||
longitude: data.longitude,
|
||||
speed: data.speed,
|
||||
heading: data.heading,
|
||||
location: {
|
||||
type: 'Point',
|
||||
coordinates: [data.longitude, data.latitude],
|
||||
},
|
||||
});
|
||||
await this.telemetryRepository.save(log);
|
||||
this.logger.debug(`Ingested telemetry for driver ${data.driver_id}`);
|
||||
return { success: true, timestamp: new Date() };
|
||||
}
|
||||
async getRecentDrivers(lat, lng, radiusMeters = 5000) {
|
||||
return this.telemetryRepository
|
||||
.createQueryBuilder('log')
|
||||
.where('ST_DWithin(log.location, ST_MakePoint(:lng, :lat)::geography, :radius)')
|
||||
.setParameters({ lat, lng, radius: radiusMeters })
|
||||
.orderBy('log.timestamp', 'DESC')
|
||||
.limit(50)
|
||||
.getMany();
|
||||
}
|
||||
};
|
||||
exports.TelemetryService = TelemetryService;
|
||||
exports.TelemetryService = TelemetryService = TelemetryService_1 = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(telemetry_entity_1.TelemetryLog)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository])
|
||||
], TelemetryService);
|
||||
//# sourceMappingURL=telemetry.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"telemetry.service.js","sourceRoot":"","sources":["../../src/telemetry/telemetry.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,6CAAmD;AACnD,qCAAqC;AACrC,yDAAkD;AAW3C,IAAM,gBAAgB,wBAAtB,MAAM,gBAAgB;IAKjB;IAJO,MAAM,GAAG,IAAI,eAAM,CAAC,kBAAgB,CAAC,IAAI,CAAC,CAAC;IAE5D,YAEU,mBAA6C;QAA7C,wBAAmB,GAAnB,mBAAmB,CAA0B;IACpD,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,IAAwB;QAGnC,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC;YAC1C,QAAQ,EAAE,IAAI,CAAC,SAAS;YACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE;gBACR,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC;aAC7C;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAIzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACrE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,GAAW,EAAE,GAAW,EAAE,eAAuB,IAAI;QAG1E,OAAO,IAAI,CAAC,mBAAmB;aAC5B,kBAAkB,CAAC,KAAK,CAAC;aACzB,KAAK,CAAC,wEAAwE,CAAC;aAC/E,aAAa,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;aACjD,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC;aAChC,KAAK,CAAC,EAAE,CAAC;aACT,OAAO,EAAE,CAAC;IACf,CAAC;CACF,CAAA;AA1CY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,EAAC,+BAAY,CAAC,CAAA;qCACF,oBAAU;GAL9B,gBAAgB,CA0C5B"}
|
||||
Reference in New Issue
Block a user