feat(webhook): add webhook endpoint and client push notifications, auto-refresh UI, and gitea id mapping fixes
This commit is contained in:
@@ -17,16 +17,23 @@ export class OpsServer {
|
||||
public secretsHandler!: handlers.SecretsHandler;
|
||||
public pipelinesHandler!: handlers.PipelinesHandler;
|
||||
public logsHandler!: handlers.LogsHandler;
|
||||
public webhookHandler!: handlers.WebhookHandler;
|
||||
|
||||
constructor(gitopsAppRef: GitopsApp) {
|
||||
this.gitopsAppRef = gitopsAppRef;
|
||||
}
|
||||
|
||||
public async start(port = 3000) {
|
||||
// Create webhook handler before server so routes register via addCustomRoutes
|
||||
this.webhookHandler = new handlers.WebhookHandler(this);
|
||||
|
||||
this.server = new plugins.typedserver.utilityservers.UtilityWebsiteServer({
|
||||
domain: 'localhost',
|
||||
feedMetadata: undefined,
|
||||
bundledContent: bundledFiles,
|
||||
addCustomRoutes: async (typedserver) => {
|
||||
this.webhookHandler.registerRoutes(typedserver);
|
||||
},
|
||||
});
|
||||
|
||||
// Chain typedrouters
|
||||
|
||||
@@ -5,3 +5,4 @@ export { GroupsHandler } from './groups.handler.ts';
|
||||
export { SecretsHandler } from './secrets.handler.ts';
|
||||
export { PipelinesHandler } from './pipelines.handler.ts';
|
||||
export { LogsHandler } from './logs.handler.ts';
|
||||
export { WebhookHandler } from './webhook.handler.ts';
|
||||
|
||||
62
ts/opsserver/handlers/webhook.handler.ts
Normal file
62
ts/opsserver/handlers/webhook.handler.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
|
||||
export class WebhookHandler {
|
||||
constructor(private opsServerRef: OpsServer) {}
|
||||
|
||||
public registerRoutes(typedserver: plugins.typedserver.TypedServer): void {
|
||||
typedserver.addRoute('/webhook/:connectionId', 'POST', async (ctx) => {
|
||||
const connectionId = ctx.params.connectionId;
|
||||
|
||||
// Validate connection exists
|
||||
const connection = this.opsServerRef.gitopsAppRef.connectionManager.getConnection(connectionId);
|
||||
if (!connection) {
|
||||
return new Response(JSON.stringify({ error: 'Connection not found' }), {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
// Parse event type from provider-specific headers
|
||||
const giteaEvent = ctx.headers.get('X-Gitea-Event');
|
||||
const gitlabEvent = ctx.headers.get('X-Gitlab-Event');
|
||||
const event = giteaEvent || gitlabEvent || 'unknown';
|
||||
const provider = giteaEvent ? 'gitea' : gitlabEvent ? 'gitlab' : 'unknown';
|
||||
|
||||
logger.info(`Webhook received: ${provider}/${event} for connection ${connection.name} (${connectionId})`);
|
||||
|
||||
// Broadcast to all connected frontends via TypedSocket
|
||||
try {
|
||||
const typedsocket = this.opsServerRef.server.typedserver.typedsocket;
|
||||
if (typedsocket) {
|
||||
const connections = await typedsocket.findAllTargetConnectionsByTag('allClients');
|
||||
for (const conn of connections) {
|
||||
const req = typedsocket.createTypedRequest<interfaces.requests.IReq_WebhookNotification>(
|
||||
'webhookNotification',
|
||||
conn,
|
||||
);
|
||||
req.fire({
|
||||
connectionId,
|
||||
provider,
|
||||
event,
|
||||
timestamp: Date.now(),
|
||||
}).catch((err: any) => {
|
||||
logger.warn(`Failed to notify client: ${err.message || err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
logger.warn(`Failed to broadcast webhook event: ${err.message || err}`);
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ ok: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('WebhookHandler routes registered');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user