Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Commit

Permalink
add flow
Browse files Browse the repository at this point in the history
  • Loading branch information
gkorland committed Sep 17, 2023
1 parent 542051d commit e505219
Show file tree
Hide file tree
Showing 20 changed files with 5,305 additions and 492 deletions.
5 changes: 3 additions & 2 deletions app/api/auth/[...nextauth]/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import GithubProvider from "next-auth/providers/github"
import { TypeORMAdapter } from "@auth/typeorm-adapter"
import { Adapter } from "next-auth/adapters";
import dataSourceOptions from "@/app/api/db/options";
import * as entities from "@/app/api/models/entities";

const authOptions: AuthOptions = {
adapter: TypeORMAdapter(dataSourceOptions) as Adapter,
const authOptions = {
adapter: TypeORMAdapter(dataSourceOptions, {entities}) as Adapter,
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID as string,
Expand Down
14 changes: 14 additions & 0 deletions app/api/db/appDataSource.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { DataSource, EntitySchema } from "typeorm";
import dataSourceOptions from "./options";
import { AccountEntity, SessionEntity, UserEntity } from "../models/entities";

export const AppDataSource = new DataSource({
...dataSourceOptions,
entities: [UserEntity, AccountEntity, SessionEntity, EntitySchema]
})

AppDataSource.initialize()
.then(() => {
// here you can start to work with your database
})
.catch((error) => console.log(error))
1 change: 1 addition & 0 deletions app/api/db/options.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { entities } from "@auth/typeorm-adapter";
import { DataSourceOptions } from "typeorm"

const env = process.env.NODE_ENV;
Expand Down
142 changes: 129 additions & 13 deletions app/api/db/route.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { ECSClient, RunTaskCommand, StartTaskCommand } from "@aws-sdk/client-ecs";
import { ECSClient, RunTaskCommand, StopTaskCommand, waitUntilTasksRunning } from "@aws-sdk/client-ecs";
import authOptions from '@/app/api/auth/[...nextauth]/options';
import { getServerSession } from "next-auth/next"
import { NextResponse } from "next/server"
import { UserEntity } from "../models/entities";
import type { NextApiRequest, NextApiResponse } from 'next'
import { AppDataSource } from "./appDataSource"
import { NextResponse } from "next/server";

const SUBNETS = process.env.SUBNETS?.split(":");
const SECURITY_GROUPS = process.env.SECURITY_GROUPS?.split(":");
const ecsClient = new ECSClient({ region: process.env.REGION });

export async function POST() {

const session = await getServerSession(authOptions)
const session = await getServerSession(authOptions)

if (!session) {
return NextResponse.json({ message: "You must be logged in." }, { status: 401 })
}

// Create ECS service client object.
const client = new ECSClient({ region:process.env.REGION });

// Start an ECS service using a predefined task in an existing cluster.
// Use FARGATE_SPOT capacity provider.
let params = {
Expand All @@ -39,13 +40,128 @@ export async function POST() {
}
};

try {
const data = await client.send(new RunTaskCommand(params));
console.debug("Success, task started!", data);
} catch (err) {
console.log("Error", err);
return NextResponse.json({ message: "Failed to start Task" }, { status: 500 })
let email = session.user?.email;

if (!email) {
return NextResponse.json({ message: "Task run failed, can't find user details" }, { status: 500 })
}

let repo = AppDataSource.getRepository(UserEntity)
let user = await repo.findOneBy({
email: email
})

// Each user is allowed to create a single Sandbox
if (!user) {
return NextResponse.json({ message: "Task run failed, can't find user details" }, { status: 500 })
}

if (user.task_arn) {
return NextResponse.json({ message: "Sandbox already exits" }, { status: 409 })
}

let ecsTask = new RunTaskCommand(params)
const data = await ecsClient.send(ecsTask);
if (data.failures?.length) {
return NextResponse.json({ message: "Task run failed" }, { status: 500 })
}
let taskArn: string | undefined = data.tasks?.[0].taskArn
if (typeof taskArn !== "string") {
console.log("Task ARN is not defined " + taskArn);
return NextResponse.json({ message: "Task run failed" }, { status: 500 })
}

user.task_arn = taskArn;
user.db_host = "localhost";
user.db_port = 6379;
user.db_password = "password";

await repo.save(user)

let waitECSTask = await waitUntilTasksRunning(
{ "client": ecsClient, "maxWaitTime": 6000, "maxDelay": 1, "minDelay": 1 },
{ "cluster": "falkordb", "tasks": [taskArn] }
)
// note: there are multiple waitECSTask states, check the documentation for more about that
if (waitECSTask.state == 'SUCCESS') {
return NextResponse.json({ message: "Task Started" }, { status: 201 })
} else {
return NextResponse.json({ message: "Task run failed" }, { status: 500 })
}

}

export async function DELETE() {

const session = await getServerSession(authOptions)

if (!session) {
return NextResponse.json({ message: "You must be logged in." }, { status: 401 })
}

let email = session.user?.email;

if (!email) {
return NextResponse.json({ message: "Task run failed, can't find user details" }, { status: 500 })
}

let repo = AppDataSource.getRepository(UserEntity)
let user = await repo.findOneBy({
email: email
})

// Stop an ECS service using a predefined task in an existing cluster.
if (!user){
return NextResponse.json({ message: "Task run failed, can't find user details" }, { status: 500 })
}

if (!user.task_arn) {
return NextResponse.json({ message: "Sandbox not found" }, { status: 404 })
}

let params = {
cluster: "falkordb",
task: user.task_arn,
reason: "User requested shutdown",
};

const data = await ecsClient.send(new StopTaskCommand(params));
user.task_arn = null;
await repo.save(user)

return NextResponse.json({ message: "Task Stopped" }, { status: 200 })
}

export async function GET() {

const session = await getServerSession(authOptions)

if (!session) {
return NextResponse.json({ message: "You must be logged in." }, { status: 401 })
}

let email = session.user?.email;

if (!email) {
return NextResponse.json({ message: "Can't find user details" }, { status: 500 })
}
let repo = AppDataSource.getRepository(UserEntity)
let user = await repo.findOneBy({
email: email
})

// Stop an ECS service using a predefined task in an existing cluster.
if (!user){
return NextResponse.json({ message: "Can't find user details" }, { status: 500 })
}
if(!user.task_arn) {
return NextResponse.json({ message: "Sandbox not found" }, { status: 404 })
}

return NextResponse.json({ message: "Task Started" })
return NextResponse.json({
host: user.db_host,
port: user.db_port,
password: user.db_password,
create_time: user.db_create_time,
}, { status: 200 })
}
15 changes: 15 additions & 0 deletions app/api/db/sandbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class Sandbox {

public host: string;
public port: number;
public password: string;
public create_time: Date;

constructor(host: string, port: number, password: string, create_time: Date) {
this.host = host;
this.port = port;
this.password = password;
this.create_time = create_time;
}
}
//# sourceMappingURL=sandbox.js.map
172 changes: 172 additions & 0 deletions app/api/models/entities.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
OneToMany,
ValueTransformer,
} from "typeorm"

const transformer: Record<"date" | "bigint", ValueTransformer> = {
date: {
from: (date: string | null) => date && new Date(parseInt(date, 10)),
to: (date?: Date) => date?.valueOf().toString(),
},
bigint: {
from: (bigInt: string | null) => bigInt && parseInt(bigInt, 10),
to: (bigInt?: number) => bigInt?.toString(),
},
}

@Entity({ name: "users" })
export class UserEntity {
@PrimaryGeneratedColumn("uuid")
id!: string

@Column({ type: "varchar", nullable: true })
name!: string | null

@Column({ type: "varchar", nullable: true, unique: true })
email!: string | null

@Column({ type: "varchar", nullable: true, transformer: transformer.date })
emailVerified!: string | null

@Column({ type: "varchar", nullable: true })
image!: string | null

@Column({ type: "varchar", nullable: true })
role!: string | null

@OneToMany(() => SessionEntity, (session) => session.userId)
sessions!: SessionEntity[]

@OneToMany(() => AccountEntity, (account) => account.userId)
accounts!: AccountEntity[]

@Column({ type: "varchar", nullable: true })
db_host!: string | null

@Column({ type: "int", nullable: true })
db_port!: number | null

@Column({ type: "varchar", nullable: true })
db_password!: string | null

@Column({ type: "varchar", nullable: true })
db_create_time!: string

@Column({ type: "varchar", nullable: true, transformer: transformer.date })
created!: string | null

@Column({ type: "varchar", nullable: true })
task_arn!: string | null

// @OneToMany(() => DatabaseEntity, (database) => database.userId)
// databases!: DatabaseEntity[]
}

@Entity({ name: "accounts" })
export class AccountEntity {
@PrimaryGeneratedColumn("uuid")
id!: string

@Column({ type: "uuid" })
userId!: string

@Column()
type!: string

@Column()
provider!: string

@Column()
providerAccountId!: string

@Column({ type: "varchar", nullable: true })
refresh_token!: string | null

@Column({ type: "varchar", nullable: true })
access_token!: string | null

@Column({
nullable: true,
type: "bigint",
transformer: transformer.bigint,
})
expires_at!: number | null

@Column({ type: "varchar", nullable: true })
token_type!: string | null

@Column({ type: "varchar", nullable: true })
scope!: string | null

@Column({ type: "varchar", nullable: true })
id_token!: string | null

@Column({ type: "varchar", nullable: true })
session_state!: string | null

@Column({ type: "varchar", nullable: true })
oauth_token_secret!: string | null

@Column({ type: "varchar", nullable: true })
oauth_token!: string | null

@ManyToOne(() => UserEntity, (user) => user.accounts, {
createForeignKeyConstraints: true,
})
user!: UserEntity
}

@Entity({ name: "sessions" })
export class SessionEntity {
@PrimaryGeneratedColumn("uuid")
id!: string

@Column({ unique: true })
sessionToken!: string

@Column({ type: "uuid" })
userId!: string

@Column({ transformer: transformer.date })
expires!: string

@ManyToOne(() => UserEntity, (user) => user.sessions)
user!: UserEntity
}

// @Entity({ name: "databases" })
// export class DatabaseEntity {
// @PrimaryGeneratedColumn("uuid")
// id!: string

// @Column({ type: "uuid" })
// userId!: string

// @Column({ type: "varchar", nullable: true })
// host!: string

// @Column({ type: "number", nullable: true })
// port!: number

// @ManyToOne(() => UserEntity, (user) => user.databases)
// user!: UserEntity
// }

@Entity({ name: "verification_tokens" })
export class VerificationTokenEntity {
@PrimaryGeneratedColumn("uuid")
id!: string

@Column()
token!: string

@Column()
identifier!: string

@Column({ transformer: transformer.date })
expires!: string
}
Loading

0 comments on commit e505219

Please sign in to comment.