Enforce Ingress-style link-crossing prevention
A new link can no longer cross any existing link from either team — segmentsIntersect() does a standard orientation-based segment test, and routes/links.ts excludes shared-endpoint pairs (fanning multiple links out of the same portal is fine, that's not a crossing). 6 new tests; 37 total passing.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { z } from 'zod';
|
||||
import { haversineMeters } from '../services/geo.js';
|
||||
import type { Claim, Place, User } from '../types.js';
|
||||
import { haversineMeters, segmentsIntersect } from '../services/geo.js';
|
||||
import type { Claim, LinkRow, Place, User } from '../types.js';
|
||||
|
||||
const linkBody = z.object({
|
||||
fromPlaceId: z.number().int(),
|
||||
@@ -23,6 +23,7 @@ export default async function linksRoutes(app: FastifyInstance) {
|
||||
const getExistingLink = db.prepare(`
|
||||
SELECT * FROM links WHERE (from_place_id = ? AND to_place_id = ?) OR (from_place_id = ? AND to_place_id = ?)
|
||||
`);
|
||||
const getAllLinks = db.prepare('SELECT * FROM links');
|
||||
const insertLink = db.prepare(`
|
||||
INSERT INTO links (from_place_id, to_place_id, team, created_by_pubkey, created_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
@@ -62,6 +63,25 @@ export default async function linksRoutes(app: FastifyInstance) {
|
||||
return reply.code(409).send({ error: 'these places are already linked' });
|
||||
}
|
||||
|
||||
// Links are physical XM beams in the sky in Ingress — a new link can't cross
|
||||
// any existing link, from either team. Links sharing an endpoint with the new
|
||||
// one aren't "crossing" (that's just a portal with multiple links fanning out).
|
||||
for (const existing of getAllLinks.all() as LinkRow[]) {
|
||||
if (
|
||||
existing.from_place_id === fromPlaceId ||
|
||||
existing.from_place_id === toPlaceId ||
|
||||
existing.to_place_id === fromPlaceId ||
|
||||
existing.to_place_id === toPlaceId
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const existingFrom = getPlace.get(existing.from_place_id) as Place;
|
||||
const existingTo = getPlace.get(existing.to_place_id) as Place;
|
||||
if (segmentsIntersect(fromPlace, toPlace, existingFrom, existingTo)) {
|
||||
return reply.code(409).send({ error: `would cross an existing link (id ${existing.id})` });
|
||||
}
|
||||
}
|
||||
|
||||
const result = insertLink.run(fromPlaceId, toPlaceId, user.team, req.userPubkey, nowSecs());
|
||||
return { id: result.lastInsertRowid, fromPlaceId, toPlaceId, team: user.team };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user