mirror of
https://github.com/2234839/web-font.git
synced 2025-05-18 01:59:21 +08:00
支持 llrt 运行时
This commit is contained in:
parent
2477caf183
commit
ad6d3b4649
@ -3,8 +3,15 @@ import { mimeTypes } from "./server/mime_type";
|
|||||||
import type { cMiddleware } from "./server/req_res";
|
import type { cMiddleware } from "./server/req_res";
|
||||||
import { SimpleHttpServer } from "./server/server";
|
import { SimpleHttpServer } from "./server/server";
|
||||||
import { path_join, readFile, stat } from "./interface";
|
import { path_join, readFile, stat } from "./interface";
|
||||||
if (global.tjs) {
|
let release_name = global.tjs ? "tjs" : globalThis?.process?.release?.name;
|
||||||
|
|
||||||
|
if (release_name === "tjs") {
|
||||||
import("./server/tjs");
|
import("./server/tjs");
|
||||||
|
} else if (release_name === "node" || release_name === "llrt") {
|
||||||
|
import("./server/node");
|
||||||
|
}
|
||||||
|
if (release_name === "llrt") {
|
||||||
|
import("./server/llrt");
|
||||||
}
|
}
|
||||||
const ROOT_DIR = "dist"; // 静态文件目录
|
const ROOT_DIR = "dist"; // 静态文件目录
|
||||||
|
|
||||||
@ -15,12 +22,12 @@ const logMiddleware: cMiddleware = async (req, res, next) => {
|
|||||||
console.log(`[${t2 - t1}ms] ${req.url.split("?")[0]}`);
|
console.log(`[${t2 - t1}ms] ${req.url.split("?")[0]}`);
|
||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
const reqs: Promise<unknown>[] = [];
|
|
||||||
|
|
||||||
const staticFileMiddleware: cMiddleware = async function (req, res, next) {
|
const staticFileMiddleware: cMiddleware = async function (req, res, next) {
|
||||||
let newRes: Response;
|
let newRes: Response;
|
||||||
if (req.method === "GET") {
|
if (req.method === "GET") {
|
||||||
const filePath = path_join(ROOT_DIR, req.url === "/" ? "index.html" : req.url);
|
const url = new URL(req.url);
|
||||||
|
const filePath = path_join(ROOT_DIR, url.pathname === "/" ? "index.html" : url.pathname);
|
||||||
try {
|
try {
|
||||||
const stats = await stat(filePath);
|
const stats = await stat(filePath);
|
||||||
|
|
||||||
@ -90,9 +97,9 @@ const corsMiddleware: cMiddleware = async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const fontApiMiddleware: cMiddleware = async (req, res, next) => {
|
const fontApiMiddleware: cMiddleware = async (req, res, next) => {
|
||||||
if (!req.url.startsWith("/api")) return next(req, res);
|
|
||||||
// 创建一个新的 URL 对象(需要一个完整的 URL,必须包含协议和主机)
|
// 创建一个新的 URL 对象(需要一个完整的 URL,必须包含协议和主机)
|
||||||
const url = new URL(req.url, "http://test.com");
|
const url = new URL(req.url, "http://test.com");
|
||||||
|
if (!url.pathname.startsWith("/api")) return next(req, res);
|
||||||
const params = new URLSearchParams(url.search);
|
const params = new URLSearchParams(url.search);
|
||||||
const font = params.get("font") || "";
|
const font = params.get("font") || "";
|
||||||
const text = params.get("text") || "";
|
const text = params.get("text") || "";
|
||||||
|
11
backend/server/node.ts
Normal file
11
backend/server/node.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { implInterface } from "../interface";
|
||||||
|
import { stat, readFile } from "fs/promises";
|
||||||
|
implInterface({
|
||||||
|
async stat(path) {
|
||||||
|
const r = await stat(path);
|
||||||
|
return r;
|
||||||
|
},
|
||||||
|
readFile(path) {
|
||||||
|
return readFile(path);
|
||||||
|
},
|
||||||
|
});
|
@ -1,5 +1,4 @@
|
|||||||
import { cMiddleware, cRequest, cResponse, type cNext } from "./req_res";
|
import { cMiddleware, cRequest, cResponse, type cNext } from "./req_res";
|
||||||
// import { createTcpServer } from "./tcp_server";
|
|
||||||
// 配置
|
// 配置
|
||||||
// 路由器类
|
// 路由器类
|
||||||
export class cRouter {
|
export class cRouter {
|
||||||
@ -28,18 +27,22 @@ export class SimpleHttpServer {
|
|||||||
private router: cRouter = new cRouter();
|
private router: cRouter = new cRouter();
|
||||||
|
|
||||||
constructor(options: { port: number; hostname?: string }) {
|
constructor(options: { port: number; hostname?: string }) {
|
||||||
console.log(`Server is listening on port ${options.port}`);
|
let release_name = global.tjs ? "tjs" : globalThis?.process?.release?.name;
|
||||||
|
console.log("[release.name]", release_name);
|
||||||
if (global.tjs) {
|
if (global.tjs) {
|
||||||
this.tjsServer(options);
|
this.tjsServer(options);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
// const server = createTcpServer((req, res) => {
|
if (release_name === "llrt" || release_name == "node") {
|
||||||
// const r = this.router.handle(req, res);
|
import("./tcp_server").then((m) => {
|
||||||
// return r;
|
const server = m.createTcpServer((socket) => {
|
||||||
// });
|
connectionHandle(socket, (req, res) => this.router.handle(req, res));
|
||||||
// server.listen(options.port, options.hostname, () => {
|
});
|
||||||
// console.log(`Server is listening on port ${options.port}`);
|
server.listen(options.port, options.hostname, () => {
|
||||||
// });
|
console.log(`Server is listening on port ${options.port}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private async tjsServer(options: { port: number; hostname?: string }) {
|
private async tjsServer(options: { port: number; hostname?: string }) {
|
||||||
const listener = (await global.tjs.listen(
|
const listener = (await global.tjs.listen(
|
||||||
@ -48,7 +51,7 @@ export class SimpleHttpServer {
|
|||||||
options.port,
|
options.port,
|
||||||
{},
|
{},
|
||||||
)) as tjs.Listener;
|
)) as tjs.Listener;
|
||||||
// listener.localAddress;
|
console.log(`Server is listening on port ${options.port}`);
|
||||||
for await (const connection of listener) {
|
for await (const connection of listener) {
|
||||||
connectionHandle(connection, this.router.handle.bind(this.router));
|
connectionHandle(connection, this.router.handle.bind(this.router));
|
||||||
}
|
}
|
||||||
@ -62,14 +65,21 @@ const decoder = new TextDecoder("utf-8");
|
|||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
// 请求头终止符
|
// 请求头终止符
|
||||||
const target = encoder.encode("\r\n\r\n");
|
const target = encoder.encode("\r\n\r\n");
|
||||||
async function connectionHandle(connection: tjs.Connection, handle: cNext) {
|
async function connectionHandle(
|
||||||
|
connection: {
|
||||||
|
readable: ReadableStream<Uint8Array>;
|
||||||
|
writable: WritableStream<Uint8Array>;
|
||||||
|
close: () => void;
|
||||||
|
},
|
||||||
|
handle: cNext,
|
||||||
|
) {
|
||||||
const { header, body } = await createStreamAfterTarget(connection.readable, target);
|
const { header, body } = await createStreamAfterTarget(connection.readable, target);
|
||||||
if (!header) {
|
if (!header) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const httpHeaderText = decoder.decode(header);
|
const httpHeaderText = decoder.decode(header);
|
||||||
const httpHeader = parseHttpRequest(httpHeaderText);
|
const httpHeader = parseHttpRequest(httpHeaderText);
|
||||||
const rawReq = new Request(httpHeader.url, {
|
const rawReq = new Request("http://" + httpHeader.headers["Host"] + httpHeader.url, {
|
||||||
method: httpHeader.method,
|
method: httpHeader.method,
|
||||||
body: httpHeader.method === "GET" || httpHeader.method === "HEAD" ? undefined : body,
|
body: httpHeader.method === "GET" || httpHeader.method === "HEAD" ? undefined : body,
|
||||||
headers: httpHeader.headers,
|
headers: httpHeader.headers,
|
||||||
@ -77,7 +87,6 @@ async function connectionHandle(connection: tjs.Connection, handle: cNext) {
|
|||||||
const rawRes = new Response();
|
const rawRes = new Response();
|
||||||
|
|
||||||
const { req, res } = await handle(rawReq, rawRes);
|
const { req, res } = await handle(rawReq, rawRes);
|
||||||
|
|
||||||
const resWriter = connection.writable.getWriter();
|
const resWriter = connection.writable.getWriter();
|
||||||
let headerText: string[] = [];
|
let headerText: string[] = [];
|
||||||
res.headers.forEach((value, key) => {
|
res.headers.forEach((value, key) => {
|
||||||
@ -86,12 +95,23 @@ async function connectionHandle(connection: tjs.Connection, handle: cNext) {
|
|||||||
const resHeaertText = `HTTP/1.1 ${res.status} OK\r\n${headerText.join("\r\n")}\r\n\r\n`;
|
const resHeaertText = `HTTP/1.1 ${res.status} OK\r\n${headerText.join("\r\n")}\r\n\r\n`;
|
||||||
await resWriter.write(encoder.encode(resHeaertText));
|
await resWriter.write(encoder.encode(resHeaertText));
|
||||||
if (res.body) {
|
if (res.body) {
|
||||||
|
// node 运行时
|
||||||
|
// 释放写入器的锁定
|
||||||
|
resWriter.releaseLock();
|
||||||
|
console.log("[connection.writable.locked]", connection.writable.locked);
|
||||||
// https://github.com/saghul/txiki.js/issues/646
|
// https://github.com/saghul/txiki.js/issues/646
|
||||||
await res.body?.pipeTo(connection.writable);
|
await res.body?.pipeTo(connection.writable);
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-expect-error
|
||||||
|
if (res._bodyInit) {
|
||||||
|
// tjs 运行时
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await resWriter.write(res._bodyInit);
|
await resWriter.write(res._bodyInit);
|
||||||
// await resWriter.write(encoder.encode(r));
|
} else {
|
||||||
|
// llrt 运行时
|
||||||
|
const buffer = new Uint8Array(await (await res.blob()).arrayBuffer());
|
||||||
|
await resWriter.write(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!resWriter.closed) {
|
if (!resWriter.closed) {
|
||||||
await resWriter.close();
|
await resWriter.close();
|
||||||
|
@ -1,54 +1,58 @@
|
|||||||
import { createServer } from "net";
|
import { createServer } from "net";
|
||||||
import { cNext, cResponse, parseRequest } from "./req_res";
|
|
||||||
// 状态码文本映射
|
|
||||||
const statusCodes: Record<number, string> = {
|
|
||||||
200: "OK",
|
|
||||||
404: "Not Found",
|
|
||||||
405: "Method Not Allowed",
|
|
||||||
500: "Internal Server Error",
|
|
||||||
};
|
|
||||||
// 创建 TCP 服务器
|
|
||||||
export function createTcpServer(handle: cNext) {
|
|
||||||
const server = createServer((socket) => {
|
|
||||||
let requestBuffer = "";
|
|
||||||
socket.on("data", async (data) => {
|
|
||||||
requestBuffer += data.toString();
|
|
||||||
|
|
||||||
// 如果收到请求头的结束标志,则处理请求
|
// 创建 TCP 服务器
|
||||||
if (requestBuffer.includes("\r\n\r\n")) {
|
export function createTcpServer(
|
||||||
const req = parseRequest(requestBuffer, socket);
|
onSocket: (socket: {
|
||||||
const res: cResponse = { statusCode: 200, headers: {}, body: "" };
|
readable: ReadableStream<Uint8Array>;
|
||||||
try {
|
writable: WritableStream<Uint8Array>;
|
||||||
// 处理请求
|
close: () => void;
|
||||||
const { res: newRes } = await handle(req, res);
|
}) => void,
|
||||||
// 发送响应
|
) {
|
||||||
socket.write(`HTTP/1.1 ${newRes.statusCode} ${statusCodes[newRes.statusCode]}\r\n`);
|
const server = createServer((socket) => {
|
||||||
Object.entries(newRes.headers).forEach(([key, value]) => {
|
const readable = new ReadableStream<Uint8Array>({
|
||||||
socket.write(`${key}: ${value}\r\n`);
|
start(controller) {
|
||||||
|
socket.on("data", (chunk) => {
|
||||||
|
controller.enqueue(new Uint8Array(chunk));
|
||||||
});
|
});
|
||||||
socket.write("\r\n");
|
|
||||||
if (typeof newRes.body === "string") {
|
socket.on("end", () => {
|
||||||
socket.write(newRes.body);
|
controller.close();
|
||||||
} else {
|
|
||||||
socket.write(newRes.body);
|
|
||||||
}
|
|
||||||
socket.end();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("[err]", error);
|
|
||||||
socket.write("HTTP/1.1 500 Internal Server Error\r\n");
|
|
||||||
socket.write("Content-Type: text/plain\r\n");
|
|
||||||
socket.write("\r\n");
|
|
||||||
socket.write("500 Internal Server Error");
|
|
||||||
socket.end();
|
|
||||||
} finally {
|
|
||||||
requestBuffer = ""; // 重置请求缓冲区
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("error", (err) => {
|
socket.on("error", (err) => {
|
||||||
console.error("Socket error:", err);
|
controller.error(err);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
socket.destroy();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建 WritableStream
|
||||||
|
const writable = new WritableStream<Uint8Array>({
|
||||||
|
write(chunk) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
socket.write(chunk, (err) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
socket.end();
|
||||||
|
},
|
||||||
|
abort(reason) {
|
||||||
|
socket.destroy(reason);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 实现 close 方法
|
||||||
|
function close() {
|
||||||
|
socket.end();
|
||||||
|
socket.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSocket({ readable, writable, close });
|
||||||
});
|
});
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fonteditor-core": "^2.4.1",
|
"fonteditor-core": "^2.4.1",
|
||||||
"solid-js": "^1.8.20"
|
"solid-js": "^1.8.20",
|
||||||
|
"web-streams-polyfill": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@txikijs/types": "^24.6.0",
|
"@txikijs/types": "^24.6.0",
|
||||||
|
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@ -14,6 +14,9 @@ importers:
|
|||||||
solid-js:
|
solid-js:
|
||||||
specifier: ^1.8.20
|
specifier: ^1.8.20
|
||||||
version: 1.8.21
|
version: 1.8.21
|
||||||
|
web-streams-polyfill:
|
||||||
|
specifier: ^4.0.0
|
||||||
|
version: 4.0.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@txikijs/types':
|
'@txikijs/types':
|
||||||
specifier: ^24.6.0
|
specifier: ^24.6.0
|
||||||
@ -1162,6 +1165,10 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
web-streams-polyfill@4.0.0:
|
||||||
|
resolution: {integrity: sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
webidl-conversions@4.0.2:
|
webidl-conversions@4.0.2:
|
||||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||||
|
|
||||||
@ -2157,6 +2164,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.1(@types/node@22.4.0)
|
vite: 5.4.1(@types/node@22.4.0)
|
||||||
|
|
||||||
|
web-streams-polyfill@4.0.0: {}
|
||||||
|
|
||||||
webidl-conversions@4.0.2: {}
|
webidl-conversions@4.0.2: {}
|
||||||
|
|
||||||
whatwg-url@7.1.0:
|
whatwg-url@7.1.0:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user