Fix service reconnection: return available offer from pool

Modified /services/:uuid endpoint to return an available (unanswered)
offer from the service's offer pool instead of always returning the
initial offer. This fixes reconnection failures where clients would
try to answer already-consumed offers.

Changes:
- Query all offers from the service's peer ID
- Return first unanswered offer
- Return 503 if no offers available

Fixes: "Offer already answered" errors on reconnection attempts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-06 13:47:00 +01:00
parent 1257867dff
commit 3efed6e9d2

View File

@@ -291,6 +291,7 @@ export function createApp(storage: Storage, config: Config) {
/** /**
* GET /services/:uuid * GET /services/:uuid
* Get service details by index UUID * Get service details by index UUID
* Returns an available (unanswered) offer from the service's pool
*/ */
app.get('/services/:uuid', async (c) => { app.get('/services/:uuid', async (c) => {
try { try {
@@ -302,19 +303,32 @@ export function createApp(storage: Storage, config: Config) {
return c.json({ error: 'Service not found' }, 404); return c.json({ error: 'Service not found' }, 404);
} }
// Get associated offer // Get the initial offer to find the peer ID
const offer = await storage.getOfferById(service.offerId); const initialOffer = await storage.getOfferById(service.offerId);
if (!offer) { if (!initialOffer) {
return c.json({ error: 'Associated offer not found' }, 404); return c.json({ error: 'Associated offer not found' }, 404);
} }
// Get all offers from this peer
const peerOffers = await storage.getOffersByPeerId(initialOffer.peerId);
// Find an unanswered offer
const availableOffer = peerOffers.find(offer => !offer.answererPeerId);
if (!availableOffer) {
return c.json({
error: 'No available offers',
message: 'All offers from this service are currently in use. Please try again later.'
}, 503);
}
return c.json({ return c.json({
serviceId: service.id, serviceId: service.id,
username: service.username, username: service.username,
serviceFqn: service.serviceFqn, serviceFqn: service.serviceFqn,
offerId: service.offerId, offerId: availableOffer.id,
sdp: offer.sdp, sdp: availableOffer.sdp,
isPublic: service.isPublic, isPublic: service.isPublic,
metadata: service.metadata ? JSON.parse(service.metadata) : undefined, metadata: service.metadata ? JSON.parse(service.metadata) : undefined,
createdAt: service.createdAt, createdAt: service.createdAt,