Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
services:
apache-httpd:
container_name: httpd-server
# apache-httpd:
# container_name: httpd-server-apache
# build:
# context: ./httpd/
# dockerfile: ./Dockerfile-apache
# args:
# - APACHE_LOG_DIR="/var/log/httpd-server/"
# restart: on-failure
# ports:
# - "8080:80"
# networks:
# - internal_net

nginx-httpd:
container_name: httpd-server-nginx
build:
context: ./httpd/
args:
- APACHE_LOG_DIR="/var/log/httpd-server/"
dockerfile: ./Dockerfile-nginx
restart: on-failure
ports:
- "8080:80"
Expand All @@ -17,7 +29,8 @@ services:
context: ./server/
restart: on-failure
depends_on:
- apache-httpd
# - apache-httpd
- nginx-httpd
networks:
- internal_net

Expand Down
4 changes: 2 additions & 2 deletions httpd/Dockerfile → httpd/Dockerfile-apache
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ COPY ./static/ /var/www/localhost/htdocs/static/

# add custom apache configs
RUN mkdir -p /etc/apache2/conf-custom
COPY ./conf/custom/ /etc/apache2/conf-custom/
COPY ./apache-conf/custom/ /etc/apache2/conf-custom/

# create logs directory (temporary disabled)
ARG APACHE_LOG_DIR
RUN mkdir -p ${APACHE_LOG_DIR}
RUN chown www-data:www-data ${APACHE_LOG_DIR}

# setup main apache configuration
COPY ./conf/httpd.conf /usr/local/apache2/conf/httpd.conf
COPY ./apache-conf/httpd.conf /usr/local/apache2/conf/httpd.conf

EXPOSE 80
7 changes: 7 additions & 0 deletions httpd/Dockerfile-nginx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM nginx:latest

COPY /nginx-conf/httpd.conf /etc/nginx/conf.d/default.conf
COPY ./static/ /var/www/html/

EXPOSE 80
#EXPOSE 443
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
# FastCGI server setup start
# ==========================

ProxyPass /fcgi-bin/ fcgi://fastcgi-server:55555/
ProxyPassReverse /fcgi-bin/ fcgi://fastcgi-server:55555/
ProxyPass /fcgi/ fcgi://fastcgi-server:55555/
ProxyPassReverse /fcgi/ fcgi://fastcgi-server:55555/

<Location "/fcgi-bin/">
<Location "/fcgi/">
Require all granted
</Location>

Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions httpd/nginx-conf/httpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
server {
listen 80;

root /var/www/html;

# Обработка статических файлов
location / {
try_files $uri $uri/ =404;
}

location /fcgi/ {
# Базовые настройки FastCGI
include fastcgi_params;

# Адрес FastCGI сервера
fastcgi_pass fastcgi-server:55555;
}
}
91 changes: 80 additions & 11 deletions httpd/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
--svg-axis-primary: oklch(75% 0.04 260);
--svg-fill-area: oklch(52% 0.07 200);

--error-bg: oklch(55% 0.15 19);

/* Всякое разное */
--btn-active-translateY: -2px;

Expand Down Expand Up @@ -231,13 +233,9 @@
}

.container {
animation: fadeIn 0.6s ease-out;
animation: containerFadeIn 0.6s ease-out;
}

.form-row {
animation: fadeIn 0.8s ease-out;
}

/* Адаптивность */
@media (max-width: 768px) {
.form-grid {
Expand Down Expand Up @@ -375,7 +373,28 @@
transform: translateY(var(--btn-active-translateY));
}

/* Адаптивность */
/* Сообщение об ошибке */
.error-message {
position: fixed;
bottom: 20px;
right: 20px;

background-color: var(--error-bg);
color: var(--text-primary);

padding: 15px 20px;

border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);

z-index: 1000;

max-width: 350px;

animation: errorSlideIn 0.3s ease-out, errorFadeOut 0.5s ease-in 4.5s forwards;
}

/* Адаптивность */
@media (max-width: 968px) {
.container {
min-width: 95%;
Expand Down Expand Up @@ -404,7 +423,7 @@
}

/* Анимации */
@keyframes fadeIn {
@keyframes containerFadeIn {
from {
opacity: 0;
transform: translateY(20px);
Expand All @@ -414,6 +433,27 @@
transform: translateY(0);
}
}

@keyframes errorSlideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}

@keyframes errorFadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
display: none;
}
}
</style>
</head>
<body>
Expand Down Expand Up @@ -633,17 +673,43 @@ <h3 class="history-title">История введенных данных</h3>
// Хранение истории данных
let formHistory = JSON.parse(localStorage.getItem('formHistory')) || [];

const showError = (message) => {
// Убираем существующие сообщения
const existingErrors = document.querySelectorAll('.error-message');
existingErrors.forEach(error => error.remove());

// Слздаём элемент
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.textContent = message;

// Вставка
document.body.appendChild(errorDiv);

// Убираем по прошествии 5-ти секунд
setTimeout(() => {
if (errorDiv.parentNode) {
errorDiv.parentNode.removeChild(errorDiv);
}
}, 5000);
};

const FFCGIResponceHandler = (responce, X, Y, R) => {
const JSONresponce = JSON.parse(responce);
const JSONResponce = JSON.parse(responce);

if (JSONResponce.error) {
showError(`Ошибка: ${JSONResponce.error}`);
return;
}

// Сохраняем данные в историю
const formData = {
timestamp: new Date().toISOString(),
X: X,
Y: Y,
R: R,
elapsedTimeNs: JSONresponce.elapsedTimeNs,
isHitted: JSONresponce.result
elapsedTimeNs: JSONResponce.elapsedTimeNs,
isHitted: JSONResponce.result
};

formHistory.push(formData);
Expand All @@ -666,7 +732,10 @@ <h3 class="history-title">История введенных данных</h3>
const Y = document.getElementById('Y').value;

if (X && R && Y) {
sendAJAXGETRequest("/fcgi-bin/", {"x": X, "y": Y, "r": R}, (resp) => {FFCGIResponceHandler(resp, X, Y, R)});

// Stub
sendAJAXGETRequest("/fcgi/", {"x": X, "y": Y, "r": R}, (data) => {FFCGIResponceHandler(data, X,Y,R)});
console.log(`Данные отправлены!\nX: ${X}\nY: ${Y}\nR: ${R}`);

// Очищаем форму
this.reset();
Expand Down
9 changes: 1 addition & 8 deletions server/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion server/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions server/src/main/java/org/validator/ValidatedRecordFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.validator;

import org.validator.validation.ValidationController;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ValidatedRecordFactory {
@SuppressWarnings("unchecked")
public static <T extends Record> T create(Class<T> recordClass, Object... args) {
try {
Constructor<T> constructor = (Constructor<T>) recordClass.getDeclaredConstructors()[0];
T record = constructor.newInstance(args);

ValidationController.validateObject(record);

return record;
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Record can't be created", e);
}
}
}
12 changes: 12 additions & 0 deletions server/src/main/java/org/validator/annotations/NotNull.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.validator.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.ANNOTATION_TYPE})
public @interface NotNull {
String errorMsg() default "Field required";
}
19 changes: 19 additions & 0 deletions server/src/main/java/org/validator/annotations/Number.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.validator.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@NotNull(errorMsg = "Number field is required")
@Size(min = 1, errorMsg = "Number must not be empty")
@Pattern(pattern = "^-?\\d+(\\.\\d+)?$", errorMsg = "Must be a valid number")
public @interface Number {
String rangeErrorMsg() default "Number must be between %s and %s";
String stepErrorMsg() default "Number distance from minimum must be divisible by %s";
double min() default Integer.MIN_VALUE;
double max() default Integer.MAX_VALUE;
double step() default 0;
}
14 changes: 14 additions & 0 deletions server/src/main/java/org/validator/annotations/Pattern.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.validator.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.ANNOTATION_TYPE})
@NotNull
public @interface Pattern {
String errorMsg() default "Pattern mismatch";
String pattern();
}
15 changes: 15 additions & 0 deletions server/src/main/java/org/validator/annotations/Size.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.validator.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.ANNOTATION_TYPE})
@NotNull
public @interface Size {
String errorMsg() default "String size must be between %d and %d";
int min() default 0;
long max() default Integer.MAX_VALUE;
}
Loading