chore: import upstream snapshot with attribution
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
RUN echo '{"name": "simple-node-app", "version": "1.0.0", "dependencies": {"ws": "^8.0.0"}}' > package.json
|
||||
RUN npm install
|
||||
|
||||
COPY ./container/simple-node-app.js app.js
|
||||
EXPOSE 8080
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN echo 'This (no-op) build takes forever...'
|
||||
RUN sleep 50000
|
||||
@@ -0,0 +1,49 @@
|
||||
const { createServer } = require("http");
|
||||
|
||||
const webSocketEnabled = process.env.WS_ENABLED === "true";
|
||||
|
||||
// Create HTTP server
|
||||
const server = createServer(function (req, res) {
|
||||
if (req.url === "/ws") {
|
||||
// WebSocket upgrade will be handled by the WebSocket server
|
||||
return;
|
||||
}
|
||||
|
||||
res.writeHead(200, { "Content-Type": "text/plain" });
|
||||
res.write("Hello World! Have an env var! " + process.env.MESSAGE);
|
||||
res.end();
|
||||
});
|
||||
|
||||
// Check if WebSocket functionality is enabled
|
||||
if (webSocketEnabled) {
|
||||
const WebSocket = require("ws");
|
||||
|
||||
// Create WebSocket server
|
||||
const wss = new WebSocket.Server({
|
||||
server: server,
|
||||
path: "/ws",
|
||||
});
|
||||
|
||||
wss.on("connection", function connection(ws) {
|
||||
console.log("WebSocket connection established");
|
||||
|
||||
ws.on("message", function message(data) {
|
||||
console.log("Received:", data.toString());
|
||||
// Echo the message back with prefix
|
||||
ws.send("Echo: " + data.toString());
|
||||
});
|
||||
|
||||
ws.on("close", function close() {
|
||||
console.log("WebSocket connection closed");
|
||||
});
|
||||
|
||||
ws.on("error", console.error);
|
||||
});
|
||||
}
|
||||
|
||||
server.listen(8080, function () {
|
||||
console.log("Server listening on port 8080");
|
||||
if (webSocketEnabled) {
|
||||
console.log("WebSocket support enabled");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { DurableObject } from "cloudflare:workers";
|
||||
|
||||
export class FixtureTestContainer extends DurableObject<Env> {
|
||||
container: globalThis.Container;
|
||||
monitor?: Promise<unknown>;
|
||||
|
||||
constructor(ctx: DurableObjectState, env: Env) {
|
||||
super(ctx, env);
|
||||
this.container = ctx.container;
|
||||
}
|
||||
|
||||
async fetch(req: Request) {
|
||||
const path = new URL(req.url).pathname;
|
||||
switch (path) {
|
||||
case "/status":
|
||||
return new Response(JSON.stringify(this.container.running));
|
||||
|
||||
case "/destroy":
|
||||
if (!this.container.running) {
|
||||
throw new Error("Container is not running.");
|
||||
}
|
||||
await this.container.destroy();
|
||||
return new Response(JSON.stringify(this.container.running));
|
||||
|
||||
case "/start":
|
||||
this.container.start({
|
||||
entrypoint: ["node", "app.js"],
|
||||
env: { MESSAGE: "I'm an env var!" },
|
||||
enableInternet: false,
|
||||
});
|
||||
// this doesn't instantly start, so we will need to poll /fetch
|
||||
return new Response("Container create request sent...");
|
||||
|
||||
case "/fetch":
|
||||
const res = await this.container
|
||||
.getTcpPort(8080)
|
||||
// actual request doesn't matter
|
||||
.fetch("http://foo/bar/baz", { method: "POST", body: "hello" });
|
||||
return new Response(await res.text());
|
||||
|
||||
case "/destroy-with-monitor":
|
||||
const monitor = this.container.monitor();
|
||||
await this.container.destroy();
|
||||
await monitor;
|
||||
return new Response("Container destroyed with monitor.");
|
||||
|
||||
default:
|
||||
return new Response("Hi from Container DO");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env): Promise<Response> {
|
||||
const url = new URL(request.url);
|
||||
if (url.pathname === "/second") {
|
||||
// This is a second Durable Object that can be used to test multiple DOs
|
||||
const id = env.CONTAINER.idFromName("second-container");
|
||||
const stub = env.CONTAINER.get(id);
|
||||
const query = url.searchParams.get("req");
|
||||
return stub.fetch("http://example.com/" + query);
|
||||
}
|
||||
const id = env.CONTAINER.idFromName("container");
|
||||
const stub = env.CONTAINER.get(id);
|
||||
return stub.fetch(request);
|
||||
},
|
||||
} satisfies ExportedHandler<Env>;
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020"],
|
||||
"types": ["@cloudflare/workers-types"],
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable */
|
||||
// Generated by Wrangler by running `wrangler types ./container-app/src/worker-configuration.d.ts -c ./container-app/wrangler.jsonc --no-include-runtime` (hash: 3e9f96a73efdcd8aacad1235e0761dab)
|
||||
interface __BaseEnv_Env {
|
||||
CONTAINER: DurableObjectNamespace<import("./index").FixtureTestContainer>;
|
||||
}
|
||||
declare namespace Cloudflare {
|
||||
interface GlobalProps {
|
||||
mainModule: typeof import("./index");
|
||||
durableNamespaces: "FixtureTestContainer";
|
||||
}
|
||||
interface Env extends __BaseEnv_Env {}
|
||||
}
|
||||
interface Env extends __BaseEnv_Env {}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "container-app",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2025-04-03",
|
||||
"containers": [
|
||||
{
|
||||
"image": "./Dockerfile",
|
||||
"class_name": "FixtureTestContainer",
|
||||
"name": "container",
|
||||
"max_instances": 2,
|
||||
},
|
||||
],
|
||||
"durable_objects": {
|
||||
"bindings": [
|
||||
{
|
||||
"class_name": "FixtureTestContainer",
|
||||
"name": "CONTAINER",
|
||||
},
|
||||
],
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"tag": "v1",
|
||||
"new_sqlite_classes": ["FixtureTestContainer"],
|
||||
},
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user