Updates
This commit is contained in:
parent
58ef4eaaae
commit
f26227c7a8
@ -15,8 +15,6 @@ type Props = {
|
||||
export default function AdminHero({ title, ctas, description }: Props) {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
console.log("pageProps.pageUrl", pageProps.pageUrl);
|
||||
|
||||
return (
|
||||
<Row className="w-full grid-cell-content justify-between">
|
||||
<Stack className="gap-2">
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import { useContext, useEffect, useRef } from "react";
|
||||
import { AppContext } from "@/src/pages/_app";
|
||||
import {
|
||||
NormalizedServerObject,
|
||||
ParsedDeploymentServiceConfig,
|
||||
WebSocketDataType,
|
||||
} from "@/src/types";
|
||||
import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver";
|
||||
import Center from "@/twui/components/layout/Center";
|
||||
import Loading from "@/twui/components/elements/Loading";
|
||||
import useWebSocketEventHandler from "@/twui/components/hooks/useWebSocketEventHandler";
|
||||
|
||||
type Props = {
|
||||
service: ParsedDeploymentServiceConfig;
|
||||
server: NormalizedServerObject;
|
||||
};
|
||||
|
||||
export default function ServiceClusterServerViews({ service, server }: Props) {
|
||||
const { pageProps, ws } = useContext(AppContext);
|
||||
|
||||
const { data } = useWebSocketEventHandler<WebSocketDataType>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!ws?.socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
ws.sendData({
|
||||
event: "client:ping",
|
||||
server,
|
||||
service,
|
||||
});
|
||||
}, [ws]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("data", data);
|
||||
}, [data]);
|
||||
|
||||
return <Stack className="gap-0 w-full"></Stack>;
|
||||
}
|
||||
@ -1,10 +1,14 @@
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import { useContext } from "react";
|
||||
import { useContext, useRef } from "react";
|
||||
import { AppContext } from "@/src/pages/_app";
|
||||
import {
|
||||
NormalizedServerObject,
|
||||
ParsedDeploymentServiceConfig,
|
||||
} from "@/src/types";
|
||||
import useIntersectionObserver from "@/twui/components/hooks/useIntersectionObserver";
|
||||
import Center from "@/twui/components/layout/Center";
|
||||
import Loading from "@/twui/components/elements/Loading";
|
||||
import ServiceClusterServerViews from "./cluster-server-views";
|
||||
|
||||
type Props = {
|
||||
service: ParsedDeploymentServiceConfig;
|
||||
@ -13,20 +17,23 @@ type Props = {
|
||||
|
||||
export default function ServiceClusterServer({ service, server }: Props) {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const { deployment, children_services } = pageProps;
|
||||
|
||||
const all_services = [service, ...(children_services || [])];
|
||||
|
||||
const deployment_name = deployment?.deployment_name;
|
||||
const service_name = service?.service_name;
|
||||
|
||||
const cluster_servers = service.servers;
|
||||
const elementRef = useRef<HTMLDivElement>(undefined);
|
||||
const { isIntersecting } = useIntersectionObserver({ elementRef });
|
||||
|
||||
return (
|
||||
<Stack className="w-full grid-cell col-span-1">
|
||||
{cluster_servers?.map((server, index) => {
|
||||
return null;
|
||||
})}
|
||||
<Stack className="grid-cell gap-0" componentRef={elementRef as any}>
|
||||
<Stack className="grid-cell-content">
|
||||
<code>{server.private_ip}</code>
|
||||
</Stack>
|
||||
<hr />
|
||||
{isIntersecting ? (
|
||||
<ServiceClusterServerViews {...{ server, service }} />
|
||||
) : (
|
||||
<Center>
|
||||
<Loading />
|
||||
</Center>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { AppContext } from "@/src/pages/_app";
|
||||
import { ParsedDeploymentServiceConfig } from "@/src/types";
|
||||
import Row from "@/twui/components/layout/Row";
|
||||
import H2 from "@/twui/components/layout/H2";
|
||||
import ServiceClusterServer from "./cluster-server";
|
||||
|
||||
type Props = {
|
||||
service: ParsedDeploymentServiceConfig;
|
||||
@ -12,25 +13,25 @@ type Props = {
|
||||
|
||||
export default function ServiceCluster({ service, cluster_index }: Props) {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const { deployment, children_services } = pageProps;
|
||||
|
||||
const all_services = [service, ...(children_services || [])];
|
||||
|
||||
const deployment_name = deployment?.deployment_name;
|
||||
const service_name = service?.service_name;
|
||||
|
||||
const cluster_servers = service.servers;
|
||||
|
||||
return (
|
||||
<Stack className="w-full grid-cell col-span-1">
|
||||
<Stack className="w-full grid-cell col-span-1 gap-0">
|
||||
<Stack className="grid-cell-content">
|
||||
<H2>Cluster #{cluster_index}</H2>
|
||||
<Row className="">
|
||||
{cluster_servers?.map((server, index) => {
|
||||
return <code>{server.private_ip}</code>;
|
||||
})}
|
||||
</Row>
|
||||
</Stack>
|
||||
<hr />
|
||||
<Row className="nested-grid-frame xl:grid-cols-2">
|
||||
{cluster_servers?.map((server, index) => {
|
||||
return (
|
||||
<ServiceClusterServer
|
||||
server={server}
|
||||
service={service}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ export default function ServiceClusters() {
|
||||
const all_services = [service, ...(children_services || [])];
|
||||
|
||||
return (
|
||||
<Stack className="w-full nested-grid-frame grid-cols-1 xl:grid-cols-2">
|
||||
<Stack className="w-full nested-grid-frame grid-cols-1">
|
||||
{all_services.map((srv, index) => {
|
||||
if (!srv) return null;
|
||||
return (
|
||||
|
||||
@ -20,4 +20,6 @@ export const AppData = {
|
||||
AuthCookieName: `x-turboci-admin-auth-key`,
|
||||
AuthCSRFCookieName: `x-turboci-admin-csrf`,
|
||||
CookieExpirationTime: 1000 * 60 * 60 * 24 * 7, // One Week
|
||||
|
||||
DynamicPortStart: 4700,
|
||||
} as const;
|
||||
|
||||
38
src/nginx/conf.d/default.conf
Normal file
38
src/nginx/conf.d/default.conf
Normal file
@ -0,0 +1,38 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size 20M;
|
||||
|
||||
# Restrict port range to 4700 and above
|
||||
location ^/ttyd/(?<port>(?:470[0-9]|47[1-9]\d|4[89]\d{2}|[5-9]\d{3}|[1-9]\d{4,}))(/.*)? {
|
||||
proxy_pass http://localhost:$port$2;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /ws {
|
||||
proxy_pass http://localhost:3773;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_connect_timeout 60s;
|
||||
|
||||
proxy_buffering off;
|
||||
keepalive_timeout 75s;
|
||||
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3772;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
83
src/nginx/default-nginx.conf
Normal file
83
src/nginx/default-nginx.conf
Normal file
@ -0,0 +1,83 @@
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
# multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
##
|
||||
# Basic Settings
|
||||
##
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
types_hash_max_size 2048;
|
||||
# server_tokens off;
|
||||
|
||||
# server_names_hash_bucket_size 64;
|
||||
# server_name_in_redirect off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
##
|
||||
# SSL Settings
|
||||
##
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
##
|
||||
# Gzip Settings
|
||||
##
|
||||
|
||||
gzip on;
|
||||
|
||||
# gzip_vary on;
|
||||
# gzip_proxied any;
|
||||
# gzip_comp_level 6;
|
||||
# gzip_buffers 16 8k;
|
||||
# gzip_http_version 1.1;
|
||||
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
}
|
||||
|
||||
|
||||
#mail {
|
||||
# # See sample authentication script at:
|
||||
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
|
||||
#
|
||||
# # auth_http localhost/auth.php;
|
||||
# # pop3_capabilities "TOP" "USER";
|
||||
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
|
||||
#
|
||||
# server {
|
||||
# listen localhost:110;
|
||||
# protocol pop3;
|
||||
# proxy on;
|
||||
# }
|
||||
#
|
||||
# server {
|
||||
# listen localhost:143;
|
||||
# protocol imap;
|
||||
# proxy on;
|
||||
# }
|
||||
#}
|
||||
91
src/nginx/default-server.conf
Normal file
91
src/nginx/default-server.conf
Normal file
@ -0,0 +1,91 @@
|
||||
##
|
||||
# You should look at the following URL's in order to grasp a solid understanding
|
||||
# of Nginx configuration files in order to fully unleash the power of Nginx.
|
||||
# https://www.nginx.com/resources/wiki/start/
|
||||
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
|
||||
# https://wiki.debian.org/Nginx/DirectoryStructure
|
||||
#
|
||||
# In most cases, administrators will remove this file from sites-enabled/ and
|
||||
# leave it as reference inside of sites-available where it will continue to be
|
||||
# updated by the nginx packaging team.
|
||||
#
|
||||
# This file will automatically load configuration files provided by other
|
||||
# applications, such as Drupal or Wordpress. These applications will be made
|
||||
# available underneath a path with that package name, such as /drupal8.
|
||||
#
|
||||
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
|
||||
##
|
||||
|
||||
# Default server configuration
|
||||
#
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
# SSL configuration
|
||||
#
|
||||
# listen 443 ssl default_server;
|
||||
# listen [::]:443 ssl default_server;
|
||||
#
|
||||
# Note: You should disable gzip for SSL traffic.
|
||||
# See: https://bugs.debian.org/773332
|
||||
#
|
||||
# Read up on ssl_ciphers to ensure a secure configuration.
|
||||
# See: https://bugs.debian.org/765782
|
||||
#
|
||||
# Self signed certs generated by the ssl-cert package
|
||||
# Don't use them in a production server!
|
||||
#
|
||||
# include snippets/snakeoil.conf;
|
||||
|
||||
root /var/www/html;
|
||||
|
||||
# Add index.php to the list if you are using PHP
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
# First attempt to serve request as file, then
|
||||
# as directory, then fall back to displaying a 404.
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# pass PHP scripts to FastCGI server
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# include snippets/fastcgi-php.conf;
|
||||
#
|
||||
# # With php-fpm (or other unix sockets):
|
||||
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
|
||||
# # With php-cgi (or other tcp sockets):
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
#}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
||||
|
||||
# Virtual Host configuration for example.com
|
||||
#
|
||||
# You can move that to a different file under sites-available/ and symlink that
|
||||
# to sites-enabled/ to enable it.
|
||||
#
|
||||
#server {
|
||||
# listen 80;
|
||||
# listen [::]:80;
|
||||
#
|
||||
# server_name example.com;
|
||||
#
|
||||
# root /var/www/example.com;
|
||||
# index index.html;
|
||||
#
|
||||
# location / {
|
||||
# try_files $uri $uri/ =404;
|
||||
# }
|
||||
#}
|
||||
34
src/nginx/nginx.conf
Normal file
34
src/nginx/nginx.conf
Normal file
@ -0,0 +1,34 @@
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@ -115,3 +115,7 @@ code {
|
||||
#admin-main h2 {
|
||||
@apply text-xl font-semibold;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply border-foreground-light/10 dark:border-foreground-dark/10;
|
||||
}
|
||||
|
||||
@ -231,6 +231,8 @@ export const WebSocketEvents = [
|
||||
export type WebSocketDataType = {
|
||||
event: (typeof WebSocketEvents)[number];
|
||||
message?: string;
|
||||
service?: ParsedDeploymentServiceConfig;
|
||||
server?: NormalizedServerObject;
|
||||
};
|
||||
|
||||
export type WebSocketType = {
|
||||
|
||||
44
src/utils/grab-next-available-port.ts
Normal file
44
src/utils/grab-next-available-port.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { dlopen, ptr, FFIType } from "bun:ffi";
|
||||
import { AppData } from "../data/app-data";
|
||||
|
||||
const libc = dlopen("libc.so.6", {
|
||||
socket: {
|
||||
args: [FFIType.i32, FFIType.i32, FFIType.i32],
|
||||
returns: FFIType.i32,
|
||||
},
|
||||
bind: {
|
||||
args: [FFIType.i32, FFIType.ptr, FFIType.i32],
|
||||
returns: FFIType.i32,
|
||||
},
|
||||
close: { args: [FFIType.i32], returns: FFIType.i32 },
|
||||
});
|
||||
|
||||
const AF_INET = 2;
|
||||
const SOCK_STREAM = 1;
|
||||
const INADDR_ANY = 0;
|
||||
|
||||
function makeSockaddr(port: number): Buffer {
|
||||
const buf = Buffer.alloc(16);
|
||||
buf.writeUInt16LE(AF_INET, 0);
|
||||
buf.writeUInt16BE(port, 2);
|
||||
buf.writeUInt32BE(INADDR_ANY, 4);
|
||||
return buf;
|
||||
}
|
||||
|
||||
export default function getNextAvailablePort(
|
||||
startPort = AppData["DynamicPortStart"],
|
||||
maxPort = 65535,
|
||||
): number {
|
||||
for (let port = startPort; port <= maxPort; port++) {
|
||||
const fd = libc.symbols.socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) continue;
|
||||
|
||||
const addr = makeSockaddr(port);
|
||||
const result = libc.symbols.bind(fd, ptr(addr), addr.byteLength);
|
||||
libc.symbols.close(fd);
|
||||
|
||||
if (result === 0) return port;
|
||||
}
|
||||
|
||||
throw new Error(`No available port found in range ${startPort}-${maxPort}`);
|
||||
}
|
||||
2
twui
2
twui
@ -1 +1 @@
|
||||
Subproject commit 9f8527fc4d851c1fecd6600bd60c490de998676f
|
||||
Subproject commit 2c101420ccc7dc1c56eb7bb7c41f2cca83af334a
|
||||
Loading…
Reference in New Issue
Block a user