0.1.2Updated 7 months ago
import type { InfinityContext } from "@infinity-beyond/infinity.ts";
import { randomUUID } from "node:crypto";

import { RequestAnalytics } from "@infinity-beyond/modules/analytics/request_analytics.ts";
import { ResponseAnalytics } from "@infinity-beyond/modules/analytics/response_analytics.ts";
import { Entity } from "@infinity-beyond/classes/entity.ts";
import State from "@infinity-beyond/modules/state.ts";
import { CustomEventEmitter } from "@infinity-beyond/classes/custom_event_emitter.ts";
import InfinityHeaders from "@infinity-beyond/modules/networking/infinity_headers.ts";

export class Infinity extends CustomEventEmitter<InfinityEvents> {
  readonly app_name: string
  constructor(app_name: string) {
    super();

    this.app_name = app_name;
  }

  async Middleware(request: Request, ctx: InfinityContext) {
    ctx.state.request_id = randomUUID();
    ctx.state.request_start_date = new Date();

    this.emit('request', request, ctx);

    await RequestAnalytics.Process(request, ctx);

    const response = await ctx.next();

    await ResponseAnalytics.Process(response, ctx)

    this.emit('response', response, ctx);

    // InfinityHeaders.apply(response.headers, {
    //   'x-request-id': ctx.state.request_id,
    //   'x-time-taken': (new Date().getTime() - ctx.state.request_start_date.getTime()).toString(),
    // }, InfinityHeaders.Default);

    // response.headers.delete('x-fresh-uuid');

    return response;
  }

  handshake(request: Request, _ctx: InfinityContext) {
    const signature = request.headers.get('sec-websocket-protocol')?.replace(/^SIGNATURE, (.+$)$/, '$1');

    if(!signature || signature !== State.SIGNATURE) {
      return new Response('Invalid signature', { status: 403 });
    }

    const { socket, response } = Deno.upgradeWebSocket(request);

    const query: Record<string, string> = new URL(request.url).search
      ?.replace(/^\?/, '')
      .split('&')
      .reduce((p, query) => {
        const [key, value] = query.split('=');
        p[key] = value;
        return p;
      }, {} as Record<string, string>) ?? {};

    const { uuid } = query;
    if(!uuid) {
      socket.close(1, 'No provided uuid');
      return new Response('', { status: 403 });
    }

    socket.onopen = () => {
      Entity.__AddWorker(uuid, socket);
    }

    return response;
  }
}

type InfinityEvents = {
  request: [request: Request, ctx: InfinityContext],
  response: [response: Response, ctx: InfinityContext],
}