up
This commit is contained in:
@@ -37,6 +37,7 @@ dependencies {
|
||||
implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion"))
|
||||
implementation("io.vertx:vertx-launcher-application")
|
||||
implementation("io.vertx:vertx-web-client")
|
||||
implementation("io.vertx:vertx-web-proxy")
|
||||
implementation("io.vertx:vertx-config")
|
||||
implementation("io.vertx:vertx-sql-client-templates")
|
||||
implementation("io.vertx:vertx-health-check")
|
||||
|
||||
@@ -34,11 +34,13 @@ services:
|
||||
environment:
|
||||
PMA_HOST: iiko-db
|
||||
PMA_PORT: 3306
|
||||
PMA_USER: root
|
||||
PMA_PASSWORD: DVjXT_kew508
|
||||
UPLOAD_LIMIT: 10M
|
||||
PMA_ABSOLUTE_URI: https://iiko-app.dev.xserver.su/phpmyadmin/
|
||||
TZ: Europe/Moscow
|
||||
ports:
|
||||
- "7102:80"
|
||||
# - "7102:80"
|
||||
|
||||
iiko-redis:
|
||||
image: redis:latest
|
||||
@@ -75,5 +77,9 @@ services:
|
||||
REDIS__HOST: iiko-redis
|
||||
REDIS__PORT: 6379
|
||||
SERVER__PORT: 7104
|
||||
PMA__ENABLED: true
|
||||
PMA__BASE_PATH: /phpmyadmin
|
||||
PMA__UPSTREAM: http://iiko-pma:80/
|
||||
|
||||
volumes:
|
||||
- $PWD/app/logs:/app/logs
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
</svg>
|
||||
</router-link>
|
||||
<a
|
||||
href="/phpmyadmin"
|
||||
href="/phpmyadmin/"
|
||||
v-if="userStore.role === 'admin'"
|
||||
target="_self"
|
||||
class="p-2 text-gray-400 hover:text-gray-600 rounded-lg hover:bg-gray-100 transition-colors"
|
||||
|
||||
@@ -6,9 +6,14 @@ import io.vertx.config.ConfigStoreOptions;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.client.HttpRequest;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import io.vertx.ext.web.handler.SessionHandler;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
@@ -23,6 +28,7 @@ import su.xserver.iikocon.iiko.IikoHandler;
|
||||
import su.xserver.iikocon.iiko.IikoOlapClient;
|
||||
import su.xserver.iikocon.service.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -42,7 +48,10 @@ public class MainVerticle extends AbstractVerticle {
|
||||
private SettingsService settingsService;
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
public void start(Promise<Void> startPromise) throws ClassNotFoundException {
|
||||
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
Class.forName("org.postgresql.Driver");
|
||||
|
||||
ConfigStoreOptions classpathStore = new ConfigStoreOptions()
|
||||
.setType("file")
|
||||
@@ -119,12 +128,107 @@ public class MainVerticle extends AbstractVerticle {
|
||||
});
|
||||
}
|
||||
|
||||
private void setupPhpmyadminProxy(Router router) {
|
||||
if (config.pma == null || !config.pma.enabled) return;
|
||||
|
||||
String upstream = config.pma.upstream;
|
||||
String basePath = config.pma.basePath;
|
||||
|
||||
final URI upstreamUri = URI.create(upstream);
|
||||
final String host = upstreamUri.getHost();
|
||||
int portTmp = upstreamUri.getPort();
|
||||
if (portTmp == -1) {
|
||||
portTmp = "https".equals(upstreamUri.getScheme()) ? 443 : 80;
|
||||
}
|
||||
final int port = portTmp;
|
||||
|
||||
final WebClient webClient = WebClient.create(vertx);
|
||||
|
||||
router.route(basePath + "/*").handler(ctx -> {
|
||||
if (ctx.session() != null && "admin".equals(ctx.session().get("role"))) {
|
||||
ctx.next();
|
||||
} else {
|
||||
ctx.response().putHeader("Location", "/").setStatusCode(302).end();
|
||||
}
|
||||
});
|
||||
|
||||
router.route(basePath + "/*").handler(ctx -> {
|
||||
String targetPathBase = ctx.request().path().substring(basePath.length());
|
||||
if (targetPathBase.isEmpty()) targetPathBase = "/";
|
||||
String targetPath = targetPathBase;
|
||||
String query = ctx.request().query();
|
||||
if (query != null && !query.isEmpty()) {
|
||||
targetPath += "?" + query;
|
||||
}
|
||||
final String targetPathFinal = targetPath;
|
||||
|
||||
final HttpRequest<Buffer> proxyReq = webClient.request(
|
||||
ctx.request().method(), port, host, targetPathFinal
|
||||
);
|
||||
|
||||
ctx.request().headers().forEach(header -> {
|
||||
if (!"host".equalsIgnoreCase(header.getKey())) {
|
||||
proxyReq.putHeader(header.getKey(), header.getValue());
|
||||
}
|
||||
});
|
||||
proxyReq.putHeader("Host", host + ":" + port);
|
||||
|
||||
ctx.request().bodyHandler(body -> {
|
||||
if (body != null && body.length() > 0) {
|
||||
proxyReq.sendBuffer(body)
|
||||
.onSuccess(resp -> sendResponse(ctx, resp))
|
||||
.onFailure(err -> sendError(ctx, err));
|
||||
} else {
|
||||
proxyReq.send()
|
||||
.onSuccess(resp -> sendResponse(ctx, resp))
|
||||
.onFailure(err -> sendError(ctx, err));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void sendResponse(RoutingContext ctx, HttpResponse<Buffer> resp) {
|
||||
ctx.response().setStatusCode(resp.statusCode());
|
||||
resp.headers().forEach(h -> ctx.response().putHeader(h.getKey(), h.getValue()));
|
||||
ctx.response().end(resp.body());
|
||||
}
|
||||
|
||||
private void sendError(RoutingContext ctx, Throwable err) {
|
||||
log.error("Proxy error: {}", err.getMessage());
|
||||
ctx.response().setStatusCode(502).end("Bad Gateway: " + err.getMessage());
|
||||
}
|
||||
|
||||
private Router initRouter(SessionHandler sessionHandler) {
|
||||
|
||||
Router router = Router.router(vertx);
|
||||
router.route().handler(BodyHandler.create());
|
||||
|
||||
router.route().handler(ctx -> {
|
||||
long start = System.currentTimeMillis();
|
||||
String method = ctx.request().method().name();
|
||||
String path = ctx.request().path();
|
||||
final String remoteIp = ctx.get("realClientIp") != null ?
|
||||
ctx.get("realClientIp") :
|
||||
ctx.request().remoteAddress().host();
|
||||
ctx.addBodyEndHandler(v -> {
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
log.info("{} {} - {} ms - {} - {}",
|
||||
method, path, duration, ctx.response().getStatusCode(), remoteIp);
|
||||
});
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
router.route().handler(ctx -> {
|
||||
String path = ctx.request().path();
|
||||
if (path != null && path.startsWith(config.pma.basePath + "/")) {
|
||||
ctx.next(); // пропускаем BodyHandler для прокси
|
||||
} else {
|
||||
BodyHandler.create().handle(ctx);
|
||||
}
|
||||
});
|
||||
router.route().handler(sessionHandler);
|
||||
|
||||
setupPhpmyadminProxy(router);
|
||||
|
||||
SecurityHandler securityHandlers = new SecurityHandler(settingsService);
|
||||
|
||||
// Обработчики безопасности
|
||||
@@ -147,21 +251,6 @@ public class MainVerticle extends AbstractVerticle {
|
||||
}
|
||||
});
|
||||
|
||||
router.route().handler(ctx -> {
|
||||
long start = System.currentTimeMillis();
|
||||
String method = ctx.request().method().name();
|
||||
String path = ctx.request().path();
|
||||
final String remoteIp = ctx.get("realClientIp") != null ?
|
||||
ctx.get("realClientIp") :
|
||||
ctx.request().remoteAddress().host();
|
||||
ctx.addBodyEndHandler(v -> {
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
log.info("{} {} - {} ms - {} - {}",
|
||||
method, path, duration, ctx.response().getStatusCode(), remoteIp);
|
||||
});
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
// ------ Раздаём Vue статику ------
|
||||
router.route("/assets/*").handler(StaticHandler.create("webroot/assets"));
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ public class AppConfig {
|
||||
public ServerConfig server;
|
||||
public DatabaseConfig database;
|
||||
public RedisConfig redis;
|
||||
public PhpMyAdminConfig pma;
|
||||
|
||||
public static AppConfig from(JsonObject json) {
|
||||
JsonObject resolved = json.copy();
|
||||
@@ -94,7 +95,8 @@ public class AppConfig {
|
||||
return new JsonObject()
|
||||
.put("server", server.json().getJsonObject("server"))
|
||||
.put("database", database.json().getJsonObject("database"))
|
||||
.put("redis", redis.json().getJsonObject("redis"));
|
||||
.put("redis", redis.json().getJsonObject("redis"))
|
||||
.put("pma", pma.json().getJsonObject("pma"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package su.xserver.iikocon.config;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
public class PhpMyAdminConfig {
|
||||
public boolean enabled;
|
||||
public String upstream;
|
||||
public String basePath;
|
||||
|
||||
public JsonObject json() {
|
||||
return new JsonObject()
|
||||
.put("pma", new JsonObject()
|
||||
.put("enabled", enabled)
|
||||
.put("upstream", upstream)
|
||||
.put("basePath", basePath)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,5 +18,10 @@
|
||||
"password": null,
|
||||
"maxPoolSize": 6,
|
||||
"maxWaitingHandlers": 6
|
||||
},
|
||||
"pma": {
|
||||
"enabled": false,
|
||||
"basePath": "/pma",
|
||||
"upstream": "http://localhost:80/"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user