Initial Commit

This commit is contained in:
2025-05-08 20:05:49 +08:00
commit 2d575e2e84
19 changed files with 1141 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
import VCLight, { VCLightApp, VCLightRequest, VCLightResponse } from "vclight";
import router from "./router";
import "./initRouter";
const app = new VCLight();
app.use(router);
app.use({
async post(request: VCLightRequest, response: VCLightResponse, app: VCLightApp) {},
async process(request: VCLightRequest, response: VCLightResponse, app: VCLightApp) {
response.headers["access-control-allow-origin"] = "*";
response.headers["access-control-allow-headers"] = "*";
}
});
export default app;
+45
View File
@@ -0,0 +1,45 @@
import Poll from "../../utils/poll";
import CONST from "../../const";
type Polls<T> = { value: Poll<T>[]; cache: T };
export const coursePolls: Polls<CoursePollData> = {
value: [],
cache: {
questionID: "",
answer: "",
flag: false
}
};
export const deepSeekPolls: Polls<DeepSeekPollData> = {
value: [],
cache: {
questionID: "",
question: "",
flag: false
}
};
export interface CoursePollData {
questionID: string;
answer: string;
flag: boolean;
}
export interface DeepSeekPollData {
questionID: string;
question: string;
flag: boolean;
}
export function pollCourse() {
const poll = new Poll<CoursePollData>(CONST.pollInterval);
coursePolls.value.push(poll);
return poll.wait();
}
export function pollDeepSeek() {
const poll = new Poll<DeepSeekPollData>(CONST.pollInterval);
deepSeekPolls.value.push(poll);
return poll.wait();
}
+4
View File
@@ -0,0 +1,4 @@
import "./routers/answer";
import "./routers/polling";
import "./routers/question";
import "./routers/test";
+4
View File
@@ -0,0 +1,4 @@
import VCLightRouter from "@vclight/router";
const router = new VCLightRouter();
export default router;
+27
View File
@@ -0,0 +1,27 @@
import router from "../router";
import { coursePolls } from "../data/polls";
router.on("/answer", async function (data, response) {
console.log(data.body);
const { questionID, answer } = data.body;
response.contentType = "application/json";
if (typeof questionID != "string" || typeof answer != "string") {
response.response = {
status: "error",
message: "questionID and answer are required"
};
return;
}
console.log("Received answer", questionID, answer);
const polls = coursePolls.value;
const pollData = {
questionID: questionID,
answer: answer,
flag: true
};
coursePolls.value = [];
polls.forEach((poll) => {
poll.resolve(pollData);
});
coursePolls.cache = pollData;
});
+48
View File
@@ -0,0 +1,48 @@
import router from "../router";
import {
CoursePollData,
coursePolls,
DeepSeekPollData,
deepSeekPolls,
pollCourse,
pollDeepSeek
} from "../data/polls";
import Poll from "../../utils/poll";
router.on("/polling", async function (data, response) {
if (data.method == "OPTIONS") {
return;
}
if (data.query.env == "course" || data.query.env == "deepseek") {
const polls = data.query.env == "course" ? coursePolls : deepSeekPolls;
if (polls.cache.flag) {
response.response = {
status: "success",
data: JSON.parse(JSON.stringify(polls.cache))
};
polls.cache.flag = false;
console.log("Polling cache", polls.cache);
return;
}
let pollData: CoursePollData | DeepSeekPollData | typeof Poll.TIMEOUT = await (data.query
.env == "course"
? pollCourse()
: pollDeepSeek());
response.contentType = "application/json";
if (pollData == Poll.TIMEOUT) {
response.response = {
status: "nothing"
};
return;
}
pollData = <CoursePollData | DeepSeekPollData>pollData;
pollData.flag = false;
response.response = {
status: "success",
data: pollData
};
console.log("Polling data", pollData);
}
});
+33
View File
@@ -0,0 +1,33 @@
import router from "../router";
import { coursePolls, deepSeekPolls } from "../data/polls";
router.on("/question", async function (data, response) {
const { question } = data.body;
const questionId = Math.random().toString(16).slice(2, 8);
response.contentType = "application/json";
if (typeof question != "string") {
response.response = {
status: "error",
message: "questionId is required"
};
return;
}
console.log("Received question", question);
const polls = deepSeekPolls.value;
coursePolls.value = [];
const pollData = {
questionID: questionId,
question: question,
flag: true
};
polls.forEach((poll) => {
poll.resolve(pollData);
});
deepSeekPolls.cache = pollData;
response.response = {
status: "success",
data: {
questionId: questionId
}
};
});
+31
View File
@@ -0,0 +1,31 @@
import router from "../router";
import { coursePolls, deepSeekPolls } from "../data/polls";
router.on("/test", async function (data, response) {
const question = "What is your name?";
const questionId = Math.random().toString(16).slice(2, 8);
response.contentType = "application/json";
console.log("Test question", question);
const polls = deepSeekPolls.value;
coursePolls.value = [];
if (polls.length == 0) {
deepSeekPolls.cache = {
questionID: questionId,
question: question,
flag: true
};
}
polls.forEach((poll) => {
poll.resolve({
questionID: questionId,
question: question,
flag: true
});
});
response.response = {
status: "success",
data: {
questionId: questionId
}
};
});
+5
View File
@@ -0,0 +1,5 @@
const CONST = {
pollInterval: 10000
};
export default CONST;
+11
View File
@@ -0,0 +1,11 @@
import * as http from "http";
import app from "./app/app";
const server = http.createServer();
server.on("request", app.httpHandler());
server.listen(3000, () => {
console.log("VCLight serve");
console.log("> Ready! Available at http://localhost:3000");
});
+27
View File
@@ -0,0 +1,27 @@
export default class Poll<T> {
protected inner: Promise<T>;
protected timer: Promise<typeof Poll.TIMEOUT>;
protected resolver: (value: T | PromiseLike<T>) => void;
static TIMEOUT = class Timeout {};
constructor(protected timeout: number) {
let resolver: (value: T | PromiseLike<T>) => void;
this.inner = new Promise<T>((r) => {
resolver = r;
});
this.resolver = resolver!;
this.timer = new Promise((resolve) => {
setTimeout(() => {
resolve(Poll.TIMEOUT);
}, timeout);
});
}
public resolve(value: T | PromiseLike<T>) {
this.resolver(value);
}
public async wait(): Promise<T | typeof Poll.TIMEOUT> {
return Promise.race([this.inner, this.timer]);
}
}