diff --git a/bogdanov_dmitry_lab_2/.gitignore b/bogdanov_dmitry_lab_2/.gitignore new file mode 100644 index 0000000..6f12951 --- /dev/null +++ b/bogdanov_dmitry_lab_2/.gitignore @@ -0,0 +1,2 @@ +data/ +result/ \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/README.md b/bogdanov_dmitry_lab_2/README.md new file mode 100644 index 0000000..1834bb3 --- /dev/null +++ b/bogdanov_dmitry_lab_2/README.md @@ -0,0 +1,41 @@ +# Лабораторная работа №2 + +## Богданов Дмитрий ПИбд-42 + +### Для выполнения была проделана следующая работа: +Были написаны и развернуты 3 сервиса: генератор файлов, 2 приложения для работы с этими файлами по вариантам 2 и 1 соответственно: + +Вариант 2 (для первого приложения): + +```Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data.``` + +Вариант 1 (для второго приложения): + +```Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.``` + +Приложения работают совместно, используя общий монтированный том для записи и получения информации: +``` + volumes: + - ./data:/var/data +``` +``` + volumes: + - ./data:/var/data + - ./result:/var/result +``` +``` + volumes: + - ./result:/var/result +``` + + +### Запуск лабораторной: +Необходимо перейти в папку с файлом docker-compose.yaml и ввести следующую команду: +``` +docker compose up --build +``` +Сервис генератора сгенерирует папки data и result, где будут сгенерированы входные файлы и файл-результат их обработки соответственно. + +## Видео с результатом запуска: + +Видео-демонстрацию работы можно посмотреть по данной [ссылке](https://drive.google.com/file/d/1CmVZjJuMStqNFFKbsMLjw4ihTiMnR7it/view). \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-1/Dockerfile b/bogdanov_dmitry_lab_2/app-1/Dockerfile new file mode 100644 index 0000000..8e7da3d --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-1/Dockerfile @@ -0,0 +1,7 @@ +FROM python:latest + +WORKDIR /app + +COPY app.py /app/ + +CMD ["python", "app.py"] \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-1/app.py b/bogdanov_dmitry_lab_2/app-1/app.py new file mode 100644 index 0000000..198331a --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-1/app.py @@ -0,0 +1,30 @@ +import os + +# Вариант 2 - Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data. +def solve(dir_files, dir_result, filename_result): + # Получаем список файлов в директории + filenames = os.listdir(dir_files) + result = '' + # Проходим через каждый файл + for filename in filenames: + filepath = os.path.join(dir_files, filename) + file = open(filepath, "r") + # Читаем первую строку, добавляем к результату + result += f"{file.readline()}" + file.close() + + # Если директории для сохранения результата нет - создаём + if not os.path.exists(dir_result): + os.makedirs(dir_result) + # Если директория с результатом не пустая - завершаем работу + if os.listdir(dir_result): + return + # Пишем результат в файл + filepath_result = os.path.join(dir_result, filename_result) + result_file = open(filepath_result, "w") + result_file.write(result) + print(f"Результат записан в файл {filepath_result}") + result_file.close() + +if __name__ == "__main__": + solve('/var/data', '/var/result', 'data.txt') \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-2/Dockerfile b/bogdanov_dmitry_lab_2/app-2/Dockerfile new file mode 100644 index 0000000..8e7da3d --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-2/Dockerfile @@ -0,0 +1,7 @@ +FROM python:latest + +WORKDIR /app + +COPY app.py /app/ + +CMD ["python", "app.py"] \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-2/app.py b/bogdanov_dmitry_lab_2/app-2/app.py new file mode 100644 index 0000000..d401506 --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-2/app.py @@ -0,0 +1,21 @@ +import os + +# Вариант 1 - Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt. +def solve(dir_input, dir_result, filename_result): + file_input = open(os.path.join(dir_input, 'data.txt')) + # Считываем все числа из файла + inputs = [int(line) for line in file_input.readlines()] + if inputs: + # Максимальное число + max_num = max(inputs) + print(f"Наибольшее число: {max_num}") + # Возводим во 2 степень + result = max(inputs) ** 2 + file_result = open(os.path.join(dir_result, filename_result), "w") + # Пишем результат в файл + file_result.write(str(result)) + print(f"Получен результат {result}") + file_result.close() + +if __name__ == "__main__": + solve("/var/result", '/var/result', 'result.txt') \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-generator/Dockerfile b/bogdanov_dmitry_lab_2/app-generator/Dockerfile new file mode 100644 index 0000000..d58d177 --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-generator/Dockerfile @@ -0,0 +1,7 @@ +FROM python:latest + +WORKDIR /app + +COPY generator.py /app/ + +CMD ["python", "generate_files.py"] \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/app-generator/generator.py b/bogdanov_dmitry_lab_2/app-generator/generator.py new file mode 100644 index 0000000..e7d2035 --- /dev/null +++ b/bogdanov_dmitry_lab_2/app-generator/generator.py @@ -0,0 +1,30 @@ +import os +import random as rnd +import string + +# Генератор названий файлов +def generate_filename(l): + return ''.join(rnd.choices(string.ascii_lowercase + string.digits, k=l)) + '.txt' + +def generate_files(dir, num_files, num_lines): + # Если директории для сохранения файлов нет - создаём + if not os.path.exists(dir): + os.makedirs(dir) + + # Если директория для сохранения файлов не пустая - завершаем работу + if os.listdir(dir): + return + + # Создание файлов + for i in range(num_files): + filename = generate_filename(20) + filepath = os.path.join(dir, filename) + + file = open(filepath, "w") + # Запись строк в файл + for j in range(num_lines): + file.write(f"{rnd.randint(-1000, 1000)}\n") + file.close() + +if __name__ == "__main__": + generate_files('/var/data', 50, 50) \ No newline at end of file diff --git a/bogdanov_dmitry_lab_2/docker-compose.yaml b/bogdanov_dmitry_lab_2/docker-compose.yaml new file mode 100644 index 0000000..3542011 --- /dev/null +++ b/bogdanov_dmitry_lab_2/docker-compose.yaml @@ -0,0 +1,27 @@ +services: + # Генератор файлов + generator: + build: + context: ./app-generator # Путь к контексту (докер файл + скрипт) + volumes: + - ./data:/var/data # Папка контейнера : папка локальная + entrypoint: python generator.py # Точка входа + + # Первое приложение + app1: + build: + context: ./app-1 # Путь к контексту + volumes: + - ./data:/var/data # Монтирование папок + - ./result:/var/result + depends_on: + - generator # Указываем, что запускается только после успешной работы сервиса generator + + # Второе приложение, настройка аналогична сервисам выше + app2: + build: + context: ./app-2 + volumes: + - ./result:/var/result + depends_on: + - app1 \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/README.md b/borschevskaya_anna_lab_4/README.md new file mode 100644 index 0000000..ce7c98a --- /dev/null +++ b/borschevskaya_anna_lab_4/README.md @@ -0,0 +1,50 @@ +# Отчет. Лабораторная работа 4 + +## Описание +В ходе лабораторной работы были изучены главы туториала о работе с RabbitMQ. Результат выполнения заданий каждой главы +отражен на скриншотах в папке /images: +- Tutorial-Task1.png +![Tutorial-Task1](images/Tutorial-Task1.png) +- Tutorial-Task2.png +![Tutorial-Task2](images/Tutorial-Task2.png) +- Tutorial-Task3.png +![Tutorial-Task3](images/Tutorial-Task3.png) + +Задание из 3-ей главы туториала было расширено условиями, которые были поставлены в задании к данной лабораторной работе. +Для демонстрации работы сервисов посредством ассинхронного общения через брокер сообщений RabbitMQ была выбрана +предметная область "Обработка заказов". + +Сервис-издатель "Publisher" публикует в очередь сообщений событие поступления заказа с некоторым номером. + +Сервисы-подписчики обрабатывают сообщения о заказах, при этом подписчики обрабатывают сообщение по-разному. Один вид +подписчика обрабатывает с задержкой в несколько секунд, другой - "мгновенно", они получают одни и те жа сообщения, +но соединены с разными очередями. +В качестве эксперимента изначально были запущены по одному экземпляру каждого вида. +На изображении Consumer2.png представлена работа мгновенно обрабатывающего подписчика. Он справляется с нагрузкой, +так как размер очереди не растет. +![Consumer 2](images/Consumer2.png) +На изображении Consumer1.png представлена работа подписчика, обрабатывающего сообщения с задержкой. Как мы видим, +в очереди накапливаются сообщения в состоянии 'Ready' - эти сообщения готовы для того, чтобы быть доставленными подписчикам. +Сервис не справляется с нагрузкой, так как отправляются сообщения быстрее, чем обрабатываются. +![Consumer 1](images/Consumer1.png) +Для того, чтобы обеспечить равную скорость отправки и обработки, увеличиваем количество экземпляров-подписчиков данного типа до трех. +На изображении видно, что теперь длина очереди не растет и система справляется с поступающими сообщениями. Также скорость "publish" и +"consumer ack" стали равны. +![Consumer 1](images/Consumer1-scaling.png) +## Как запустить +Для того, чтобы запустить сервисы, необходимо выполнить следующие действия: +1. Установить и запустить Docker Engine или Docker Desktop +2. Через консоль перейти в папку, в которой расположен файл docker-compose.yml +3. Выполнить команду для запуска брокера сообщений rabbitmq: +``` +docker compose up rabbit -d +``` +4. Выполнить команду для запуска остальных контейнеров: +``` +docker compose up -d +``` +Такой порядок запуска важен для того, чтобы брокер сообщений успел полностью запуститься +и произвести действия для того, чтобы быть готовым принимать соединения от сервисов. Потому что указания depends_on не хватает +для отслеживания завершения всех необходимых подготовительных процессов брокера. +## Видео-отчет +Работоспособность лабораторной работы можно оценить в следующем [видео](https://disk.yandex.ru/i/G0vsfp7vwazYHw). \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/consumer-app/Dockerfile b/borschevskaya_anna_lab_4/consumer-app/Dockerfile new file mode 100644 index 0000000..30fc690 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/Dockerfile @@ -0,0 +1,23 @@ +# Используем образ Maven для сборки +FROM maven:3.8-eclipse-temurin-21-alpine AS build + +# Устанавливаем рабочую директорию +WORKDIR /app + +# Копируем остальные исходные файлы +COPY pom.xml . +COPY src src + +# Собираем весь проект +RUN mvn clean package -DskipTests +RUN mvn dependency:copy-dependencies + +# Используем официальный образ JDK для запуска собранного jar-файла +FROM eclipse-temurin:21-jdk-alpine + +# Копируем jar-файл из предыдущего этапа +COPY --from=build /app/target/*.jar /app.jar +COPY --from=build /app/target/dependency / + +# Указываем команду для запуска приложения +CMD ["java", "-jar", "app.jar"] diff --git a/borschevskaya_anna_lab_4/consumer-app/pom.xml b/borschevskaya_anna_lab_4/consumer-app/pom.xml new file mode 100644 index 0000000..a8ee175 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.somecompany + consumer-app + 1.0.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + + + 21 + 21 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + com.rabbitmq + amqp-client + 5.22.0 + + + org.projectlombok + lombok + 1.18.30 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/Main.java b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/Main.java new file mode 100644 index 0000000..c541a18 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/Main.java @@ -0,0 +1,15 @@ +package ru.somecompany; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import ru.somecompany.config.property.RabbitProperties; + +@SpringBootApplication +@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class) +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java new file mode 100644 index 0000000..3dadb49 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java @@ -0,0 +1,45 @@ +package ru.somecompany.config; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.somecompany.config.property.RabbitProperties; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +@Configuration +@RequiredArgsConstructor +public class ConnectionFactoryConfig { + + private final RabbitProperties rabbitProperties; + + @Bean + public ConnectionFactory connectionFactory() { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost(rabbitProperties.getHost()); + factory.setPort(rabbitProperties.getPort()); + return factory; + } + + @Bean + public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + return connectionFactory.newConnection(); + } + + @Bean + public Channel channel(Connection connection) throws IOException { + var exchange = rabbitProperties.getExchange(); + var queue = rabbitProperties.getQueue(); + var channel = connection.createChannel(); + + channel.exchangeDeclare(exchange, BuiltinExchangeType.FANOUT); + channel.queueDeclare(queue, true, false, true, null); + channel.queueBind(queue, exchange, ""); + return channel; + } +} diff --git a/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java new file mode 100644 index 0000000..25f73f7 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java @@ -0,0 +1,19 @@ +package ru.somecompany.config.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "app.rabbit-properties") +public class RabbitProperties { + + private String host; + + private Integer port; + + private Integer delay; + + private String queue; + + private String exchange; +} diff --git a/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/consumer/Consumer.java b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/consumer/Consumer.java new file mode 100644 index 0000000..4f0d5b6 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/src/main/java/ru/somecompany/consumer/Consumer.java @@ -0,0 +1,76 @@ +package ru.somecompany.consumer; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.somecompany.config.property.RabbitProperties; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@RequiredArgsConstructor +public class Consumer { + + private final RabbitProperties rabbitProperties; + + private final Connection connection; + private final Channel channel; + + @PostConstruct + public void consume() { + try { + channel.basicQos(1); + channel.basicConsume(rabbitProperties.getQueue(), false, new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, + Envelope envelope, + AMQP.BasicProperties properties, + byte[] body) throws IOException { + long deliveryTag = envelope.getDeliveryTag(); + + String message = new String(body, StandardCharsets.UTF_8); + System.out.println(" [x] Received '" + message + "'"); + + var delay = rabbitProperties.getDelay(); + try { + doWork(delay); + } finally { + System.out.println(" [x] Processed '" + message + "'"); + channel.basicAck(deliveryTag, false); + } + } + }); + } catch (Exception exception) { + log.error("Error while set up connection with rabbit", exception); + } + } + + private static void doWork(Integer delay) { + if (delay > 0) { + try { + Thread.sleep(delay); + } catch (InterruptedException _ignored) { + Thread.currentThread().interrupt(); + } + } + } + + @PreDestroy + public void cleanUp() throws Exception { + if (channel != null) { + channel.close(); + } + if (connection != null) { + connection.close(); + } + } +} diff --git a/borschevskaya_anna_lab_4/consumer-app/src/main/resources/application.yml b/borschevskaya_anna_lab_4/consumer-app/src/main/resources/application.yml new file mode 100644 index 0000000..a7cded6 --- /dev/null +++ b/borschevskaya_anna_lab_4/consumer-app/src/main/resources/application.yml @@ -0,0 +1,10 @@ +server: + port: ${SERVER_PORT:8081} + +app: + rabbit-properties: + host: ${RABBIT_HOST:localhost} + port: ${RABBIT_PORT:5672} + delay: ${PROCESS_DELAY:0} + queue: ${QUEUE_NAME:queue-1} + exchange: ${EXCHANGE_NAME:order-events} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/docker-compose.yml b/borschevskaya_anna_lab_4/docker-compose.yml new file mode 100644 index 0000000..a59cc51 --- /dev/null +++ b/borschevskaya_anna_lab_4/docker-compose.yml @@ -0,0 +1,79 @@ +services: + rabbit: + container_name: rabbit + image: rabbitmq:3-management + ports: + - "15672:15672" + - "5672:5672" + - "5671:5671" + networks: + - local + publisher: + build: ./publisher-app + container_name: publisher + depends_on: + - rabbit + environment: + RABBIT_HOST: rabbit + RABBIT_PORT: 5672 + networks: + - local + consumer-1: + build: ./consumer-app + container_name: consumer-1 + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_PORT: 5672 + PROCESS_DELAY: 3000 + QUEUE_NAME: queue1 + EXCHANGE_NAME: order-events + networks: + - local + consumer-2: + build: ./consumer-app + container_name: consumer-2 + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_PORT: 5672 + PROCESS_DELAY: 0 + QUEUE_NAME: queue2 + EXCHANGE_NAME: order-events + networks: + - local + consumer-12: + build: ./consumer-app + container_name: consumer-12 + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_PORT: 5672 + PROCESS_DELAY: 3000 + QUEUE_NAME: queue1 + EXCHANGE_NAME: order-events + networks: + - local + consumer-13: + build: ./consumer-app + container_name: consumer-13 + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_PORT: 5672 + PROCESS_DELAY: 3000 + QUEUE_NAME: queue1 + EXCHANGE_NAME: order-events + networks: + - local + +networks: + local: \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/helloworld-tutorial/pom.xml b/borschevskaya_anna_lab_4/helloworld-tutorial/pom.xml new file mode 100644 index 0000000..2a85c45 --- /dev/null +++ b/borschevskaya_anna_lab_4/helloworld-tutorial/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + ru.somecompany + helloworld-tutorial + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + com.rabbitmq + amqp-client + 5.22.0 + + + org.slf4j + slf4j-api + 1.7.5 + + + org.slf4j + slf4j-log4j12 + 1.7.5 + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Main.java b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Main.java new file mode 100644 index 0000000..13f9f54 --- /dev/null +++ b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Main.java @@ -0,0 +1,28 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DeliverCallback; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeoutException; + +public class Main { + + private static final String QUEUE_NAME = "hello-world"; + + public static void main(String[] args) { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + try(Connection connection = factory.newConnection(); + Channel channel = connection.createChannel();) { + var sender = new Sender(channel); + var receiver = new Receiver(channel); + + } catch (Exception e) { + System.out.println(" [*] Error in Hello-World"); + } + } +} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Receiver.java b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Receiver.java new file mode 100644 index 0000000..ce8f740 --- /dev/null +++ b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Receiver.java @@ -0,0 +1,20 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DeliverCallback; + +import java.io.IOException; + +public class Receiver { + + private static final String QUEUE_NAME = "hello-world"; + + public Receiver(Channel channel) throws IOException { + channel.queueDeclare(QUEUE_NAME, false, false, false, null); + DeliverCallback deliverCallback = (consumerTag, delivery) -> { + String message = new String(delivery.getBody(), "UTF-8"); + System.out.println(" [x] Received '" + message + "'"); + }; + channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { }); + } +} diff --git a/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Sender.java b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Sender.java new file mode 100644 index 0000000..05afcfc --- /dev/null +++ b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/java/ru/somecompany/Sender.java @@ -0,0 +1,18 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class Sender { + + private static final String QUEUE_NAME = "hello-world"; + + public Sender(Channel channel) throws IOException { + channel.queueDeclare(QUEUE_NAME, false, false, false, null); + String message = "Hello World!"; + channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8)); + System.out.println(" [x] Sent '" + message + "'"); + } +} diff --git a/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/resources/log4j.properties b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/resources/log4j.properties new file mode 100644 index 0000000..393e087 --- /dev/null +++ b/borschevskaya_anna_lab_4/helloworld-tutorial/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +# Root logger option +log4j.rootLogger=INFO, stdout + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/images/Consumer1-scaling.PNG b/borschevskaya_anna_lab_4/images/Consumer1-scaling.PNG new file mode 100644 index 0000000..9a87b2b Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Consumer1-scaling.PNG differ diff --git a/borschevskaya_anna_lab_4/images/Consumer1.PNG b/borschevskaya_anna_lab_4/images/Consumer1.PNG new file mode 100644 index 0000000..7c60be9 Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Consumer1.PNG differ diff --git a/borschevskaya_anna_lab_4/images/Consumer2.PNG b/borschevskaya_anna_lab_4/images/Consumer2.PNG new file mode 100644 index 0000000..9592d50 Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Consumer2.PNG differ diff --git a/borschevskaya_anna_lab_4/images/Tutorial-Task1.PNG b/borschevskaya_anna_lab_4/images/Tutorial-Task1.PNG new file mode 100644 index 0000000..b2129cd Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Tutorial-Task1.PNG differ diff --git a/borschevskaya_anna_lab_4/images/Tutorial-Task2.PNG b/borschevskaya_anna_lab_4/images/Tutorial-Task2.PNG new file mode 100644 index 0000000..e29defd Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Tutorial-Task2.PNG differ diff --git a/borschevskaya_anna_lab_4/images/Tutorial-Task3.PNG b/borschevskaya_anna_lab_4/images/Tutorial-Task3.PNG new file mode 100644 index 0000000..e77d7af Binary files /dev/null and b/borschevskaya_anna_lab_4/images/Tutorial-Task3.PNG differ diff --git a/borschevskaya_anna_lab_4/publisher-app/.gitignore b/borschevskaya_anna_lab_4/publisher-app/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/publisher-app/Dockerfile b/borschevskaya_anna_lab_4/publisher-app/Dockerfile new file mode 100644 index 0000000..cc673eb --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/Dockerfile @@ -0,0 +1,21 @@ +# Используем образ Maven для сборки +FROM maven:3.8-eclipse-temurin-21-alpine AS build + +# Устанавливаем рабочую директорию +WORKDIR /app + +# Копируем остальные исходные файлы +COPY pom.xml . +COPY src src + +# Собираем весь проект +RUN mvn clean package -DskipTests + +# Используем официальный образ JDK для запуска собранного jar-файла +FROM eclipse-temurin:21-jdk-alpine + +# Копируем jar-файл из предыдущего этапа +COPY --from=build /app/target/*.jar /app.jar + +# Указываем команду для запуска приложения +CMD ["java", "-jar", "app.jar"] diff --git a/borschevskaya_anna_lab_4/publisher-app/pom.xml b/borschevskaya_anna_lab_4/publisher-app/pom.xml new file mode 100644 index 0000000..4cfb240 --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + ru.somecompany + publisher-app + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 3.2.3 + + + + + 21 + 21 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + 1.18.30 + + + com.rabbitmq + amqp-client + 5.22.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/Main.java b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/Main.java new file mode 100644 index 0000000..1ce208a --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/Main.java @@ -0,0 +1,17 @@ +package ru.somecompany; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.scheduling.annotation.EnableScheduling; +import ru.somecompany.config.property.RabbitProperties; + +@EnableScheduling +@SpringBootApplication +@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class) +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java new file mode 100644 index 0000000..0cef48f --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/ConnectionFactoryConfig.java @@ -0,0 +1,40 @@ +package ru.somecompany.config; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.somecompany.config.property.RabbitProperties; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +@Configuration +@RequiredArgsConstructor +public class ConnectionFactoryConfig { + + private final RabbitProperties rabbitProperties; + + @Bean + public ConnectionFactory connectionFactory() { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost(rabbitProperties.getHost()); + factory.setPort(rabbitProperties.getPort()); + return factory; + } + + @Bean + public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + return connectionFactory.newConnection(); + } + + @Bean + public Channel channel(Connection connection) throws IOException { + var channel = connection.createChannel(); + channel.exchangeDeclare(rabbitProperties.getExchange(), BuiltinExchangeType.FANOUT); + return channel; + } +} diff --git a/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java new file mode 100644 index 0000000..29a8bc5 --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/config/property/RabbitProperties.java @@ -0,0 +1,15 @@ +package ru.somecompany.config.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "app.rabbit-properties") +public class RabbitProperties { + + private String host; + + private Integer port; + + private String exchange; +} diff --git a/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/scheduler/SenderScheduler.java b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/scheduler/SenderScheduler.java new file mode 100644 index 0000000..66fed4c --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/src/main/java/ru/somecompany/scheduler/SenderScheduler.java @@ -0,0 +1,41 @@ +package ru.somecompany.scheduler; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeoutException; + +@Service +@RequiredArgsConstructor +public class SenderScheduler { + + private static final String EXCHANGE_NAME = "order-events"; + private static final String MESSAGE = "Поступил заказ №%d"; + private Integer index = 0; + + private final ConnectionFactory connectionFactory; + private final Connection connection; + private final Channel channel; + + @Scheduled(cron = "*/1 * * * * *") + public void sendMessage() { + try { + var message = String.format(MESSAGE, index); + + channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8)); + index++; + System.out.println(" [x] Sent '" + message + "'"); + } catch (IOException e) { + System.out.println(" [x] Error while send message"); + throw new RuntimeException(e); + } + } + +} diff --git a/borschevskaya_anna_lab_4/publisher-app/src/main/resources/application.yml b/borschevskaya_anna_lab_4/publisher-app/src/main/resources/application.yml new file mode 100644 index 0000000..983abc0 --- /dev/null +++ b/borschevskaya_anna_lab_4/publisher-app/src/main/resources/application.yml @@ -0,0 +1,8 @@ +server: + port: ${SERVER_PORT:8080} + +app: + rabbit-properties: + host: ${RABBIT_HOST:localhost} + port: ${RABBIT_PORT:5672} + exchange: ${EXCHANGE_NAME:order-events} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/workqueue-tutorial/pom.xml b/borschevskaya_anna_lab_4/workqueue-tutorial/pom.xml new file mode 100644 index 0000000..4a67d9f --- /dev/null +++ b/borschevskaya_anna_lab_4/workqueue-tutorial/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + ru.somecompany + workqueue-tutorial + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + com.rabbitmq + amqp-client + 5.22.0 + + + org.slf4j + slf4j-log4j12 + 1.7.5 + + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Main.java b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Main.java new file mode 100644 index 0000000..8e49bb1 --- /dev/null +++ b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Main.java @@ -0,0 +1,23 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Main { + + public static final String QUEUE_NAME = "task_queue"; + + public static void main(String[] args) { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + try(Connection connection = factory.newConnection(); + Channel channel = connection.createChannel();) { + var sender = new Sender(channel); + sender.send("Work Queue message"); + var receiver = new Receiver(channel); + } catch (Exception e) { + System.out.println(" [*] Error in Work-Queue: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Receiver.java b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Receiver.java new file mode 100644 index 0000000..4569eef --- /dev/null +++ b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Receiver.java @@ -0,0 +1,44 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DeliverCallback; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static ru.somecompany.Main.QUEUE_NAME; + +public class Receiver { + + public Receiver(Channel channel) throws IOException { + channel.queueDeclare(QUEUE_NAME, true, false, false, null); + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + channel.basicQos(1); + + DeliverCallback deliverCallback = (consumerTag, delivery) -> { + String message = new String(delivery.getBody(), StandardCharsets.UTF_8); + + System.out.println(" [x] Received '" + message + "'"); + try { + doWork(message); + } finally { + System.out.println(" [x] Done"); + channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); + } + }; + channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { }); + } + + private static void doWork(String task) { + for (char ch : task.toCharArray()) { + if (ch == '.') { + try { + Thread.sleep(1000); + } catch (InterruptedException _ignored) { + Thread.currentThread().interrupt(); + } + } + } + } +} diff --git a/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Sender.java b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Sender.java new file mode 100644 index 0000000..3b7ea29 --- /dev/null +++ b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/java/ru/somecompany/Sender.java @@ -0,0 +1,29 @@ +package ru.somecompany; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.MessageProperties; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +import static ru.somecompany.Main.QUEUE_NAME; + +public class Sender { + + private Channel channel; + + public Sender(Channel channel) throws IOException { + channel.queueDeclare(QUEUE_NAME, true, false, false, null); + this.channel = channel; + } + + public void send(String msg) throws IOException { + String message = String.join(" ", msg); + + channel.basicPublish("", QUEUE_NAME, + MessageProperties.PERSISTENT_TEXT_PLAIN, + message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + message + "'"); + } +} diff --git a/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/resources/log4j.properties b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/resources/log4j.properties new file mode 100644 index 0000000..393e087 --- /dev/null +++ b/borschevskaya_anna_lab_4/workqueue-tutorial/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +# Root logger option +log4j.rootLogger=INFO, stdout + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerDelay/.dockerignore b/dozorova_alena_lab_4/ConsumerDelay/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj new file mode 100644 index 0000000..a04999b --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0 + enable + enable + Linux + . + + + + + + + + diff --git a/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj.user b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj.user new file mode 100644 index 0000000..dd2d54c --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj.user @@ -0,0 +1,6 @@ + + + + Container (Dockerfile) + + \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.sln b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.sln new file mode 100644 index 0000000..f3a6ad6 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35004.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerDelay", "ConsumerDelay.csproj", "{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3E7AED20-0868-42FE-9C39-581BC9D2BB22} + EndGlobalSection +EndGlobal diff --git a/dozorova_alena_lab_4/ConsumerDelay/Dockerfile b/dozorova_alena_lab_4/ConsumerDelay/Dockerfile new file mode 100644 index 0000000..e47b674 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/Dockerfile @@ -0,0 +1,22 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["ConsumerDelay.csproj", "."] +RUN dotnet restore "./ConsumerDelay.csproj" +COPY . . +WORKDIR "/src/." +RUN dotnet build "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "ConsumerDelay.dll"] \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerDelay/Program.cs b/dozorova_alena_lab_4/ConsumerDelay/Program.cs new file mode 100644 index 0000000..8882de6 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/Program.cs @@ -0,0 +1,24 @@ +using ConsumerDelay; + +var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost"; +var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user"; +var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password"; +var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn"; +var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "Second"; + +Thread.Sleep(2000); + +var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword); + +receiver.SubscribeTo(rabbitExchange, (message) => +{ + var rnd = new Random(); + + Console.WriteLine($"Пришло сообщение: {message}"); + + Thread.Sleep(rnd.Next(2000, 3000)); + Console.WriteLine($"Обработка сообщения завершена"); +}, +rabbitQueue); + +while (true) ; \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerDelay/Receiver.cs b/dozorova_alena_lab_4/ConsumerDelay/Receiver.cs new file mode 100644 index 0000000..f4e488b --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerDelay/Receiver.cs @@ -0,0 +1,82 @@ +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using System.Text; + +namespace ConsumerDelay +{ + public class Receiver : IDisposable + { + private readonly ConnectionFactory _connectionFactory; + private readonly IConnection _connection; + private readonly IModel _channel; + + public Dictionary> Queues { get; private set; } = new(); + + public Receiver(string brockerHost, string brockerUsername, string brockerPassword) + { + _connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword }; + _connection = _connectionFactory.CreateConnection(); + _channel = _connection.CreateModel(); + } + + public bool SubscribeTo(string exchange, Action handler, string? queueName = null) + { + try + { + if (!Queues.ContainsKey(exchange)) + { + _channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout); + Queues.Add(exchange, new HashSet()); + } + if (queueName != null) + _channel.QueueDeclare(queue: queueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + + queueName = queueName ?? _channel.QueueDeclare().QueueName; + + + _channel.QueueBind(queue: queueName, + exchange: exchange, + routingKey: string.Empty); + + var consumer = new EventingBasicConsumer(_channel); + consumer.Received += (model, ea) => + { + try + { + var message = Encoding.UTF8.GetString(ea.Body.ToArray()); + handler(message); + _channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + }; + _channel.BasicConsume(queue: queueName, + autoAck: false, + consumer: consumer); + + Queues[exchange].Add(queueName); + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return false; + } + + ~Receiver() => Dispose(); + + public void Dispose() + { + _connection.Dispose(); + _channel.Dispose(); + } + } +} diff --git a/dozorova_alena_lab_4/ConsumerSimple/.dockerignore b/dozorova_alena_lab_4/ConsumerSimple/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj new file mode 100644 index 0000000..a04999b --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0 + enable + enable + Linux + . + + + + + + + + diff --git a/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj.user b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj.user new file mode 100644 index 0000000..dd2d54c --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj.user @@ -0,0 +1,6 @@ + + + + Container (Dockerfile) + + \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.sln b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.sln new file mode 100644 index 0000000..64dba82 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35004.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerSimple", "ConsumerSimple.csproj", "{ACA8DE52-E29E-41BA-B3DA-213AF316685E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {73265D6C-436C-470E-AE8A-17047E6C2ECC} + EndGlobalSection +EndGlobal diff --git a/dozorova_alena_lab_4/ConsumerSimple/Dockerfile b/dozorova_alena_lab_4/ConsumerSimple/Dockerfile new file mode 100644 index 0000000..92d16b0 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/Dockerfile @@ -0,0 +1,22 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["ConsumerSimple.csproj", "."] +RUN dotnet restore "./ConsumerSimple.csproj" +COPY . . +WORKDIR "/src/." +RUN dotnet build "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "ConsumerSimple.dll"] \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerSimple/Program.cs b/dozorova_alena_lab_4/ConsumerSimple/Program.cs new file mode 100644 index 0000000..5aab041 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/Program.cs @@ -0,0 +1,23 @@ +using ConsumerSimple; + +var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost"; +var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user"; +var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password"; +var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn"; +var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "First"; + +Thread.Sleep(2000); + +var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword); + +receiver.SubscribeTo(rabbitExchange, (message) => +{ + var rnd = new Random(); + + Console.WriteLine($"Пришло сообщение: {message}"); + + Console.WriteLine($"Сообщение обрабатывается мгновенно"); +}, +rabbitQueue); + +while (true) ; \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerSimple/Properties/launchSettings.json b/dozorova_alena_lab_4/ConsumerSimple/Properties/launchSettings.json new file mode 100644 index 0000000..b9fc529 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "ConsumerSimple": { + "commandName": "Project" + }, + "Container (Dockerfile)": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/dozorova_alena_lab_4/ConsumerSimple/Receiver.cs b/dozorova_alena_lab_4/ConsumerSimple/Receiver.cs new file mode 100644 index 0000000..9efdd27 --- /dev/null +++ b/dozorova_alena_lab_4/ConsumerSimple/Receiver.cs @@ -0,0 +1,82 @@ +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using System.Text; + +namespace ConsumerSimple +{ + public class Receiver : IDisposable + { + private readonly ConnectionFactory _connectionFactory; + private readonly IConnection _connection; + private readonly IModel _channel; + + public Dictionary> Queues { get; private set; } = new(); + + public Receiver(string brockerHost, string brockerUsername, string brockerPassword) + { + _connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword }; + _connection = _connectionFactory.CreateConnection(); + _channel = _connection.CreateModel(); + } + + public bool SubscribeTo(string exchange, Action handler, string? queueName = null) + { + try + { + if (!Queues.ContainsKey(exchange)) + { + _channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout); + Queues.Add(exchange, new HashSet()); + } + if (queueName != null) + _channel.QueueDeclare(queue: queueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + + queueName = queueName ?? _channel.QueueDeclare().QueueName; + + + _channel.QueueBind(queue: queueName, + exchange: exchange, + routingKey: string.Empty); + + var consumer = new EventingBasicConsumer(_channel); + consumer.Received += (model, ea) => + { + try + { + var message = Encoding.UTF8.GetString(ea.Body.ToArray()); + handler(message); + _channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + }; + _channel.BasicConsume(queue: queueName, + autoAck: false, + consumer: consumer); + + Queues[exchange].Add(queueName); + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return false; + } + + ~Receiver() => Dispose(); + + public void Dispose() + { + _connection.Dispose(); + _channel.Dispose(); + } + } +} diff --git a/dozorova_alena_lab_4/EmitLog/EmitLog..csproj b/dozorova_alena_lab_4/EmitLog/EmitLog..csproj new file mode 100644 index 0000000..efea465 --- /dev/null +++ b/dozorova_alena_lab_4/EmitLog/EmitLog..csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + EmitLog_ + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/EmitLog/Program.cs b/dozorova_alena_lab_4/EmitLog/Program.cs new file mode 100644 index 0000000..73120f4 --- /dev/null +++ b/dozorova_alena_lab_4/EmitLog/Program.cs @@ -0,0 +1,24 @@ +using System.Text; +using RabbitMQ.Client; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout); + +var message = GetMessage(args); +var body = Encoding.UTF8.GetBytes(message); +channel.BasicPublish(exchange: "logs", + routingKey: string.Empty, + basicProperties: null, + body: body); +Console.WriteLine($" [x] Sent {message}"); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); + +static string GetMessage(string[] args) +{ + return ((args.Length > 0) ? string.Join(" ", args) : "info: Hello World!"); +} \ No newline at end of file diff --git a/dozorova_alena_lab_4/NewTask/NewTask.csproj b/dozorova_alena_lab_4/NewTask/NewTask.csproj new file mode 100644 index 0000000..f72406b --- /dev/null +++ b/dozorova_alena_lab_4/NewTask/NewTask.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/NewTask/Program.cs b/dozorova_alena_lab_4/NewTask/Program.cs new file mode 100644 index 0000000..0928eb7 --- /dev/null +++ b/dozorova_alena_lab_4/NewTask/Program.cs @@ -0,0 +1,32 @@ +using System.Text; +using RabbitMQ.Client; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.QueueDeclare(queue: "task_queue", + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + +var message = GetMessage(args); +var body = Encoding.UTF8.GetBytes(message); + +var properties = channel.CreateBasicProperties(); +properties.Persistent = true; + +channel.BasicPublish(exchange: string.Empty, + routingKey: "task_queue", + basicProperties: properties, + body: body); +Console.WriteLine($" [x] Sent {message}"); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); + +static string GetMessage(string[] args) +{ + return ((args.Length > 0) ? string.Join(" ", args) : "Hello World!"); +} \ No newline at end of file diff --git a/dozorova_alena_lab_4/Publisher/.dockerignore b/dozorova_alena_lab_4/Publisher/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/dozorova_alena_lab_4/Publisher/Dockerfile b/dozorova_alena_lab_4/Publisher/Dockerfile new file mode 100644 index 0000000..80db941 --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Publisher.csproj", "."] +RUN dotnet restore "./Publisher.csproj" +COPY . . +WORKDIR "/src/." +RUN dotnet build "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Publisher.dll"] \ No newline at end of file diff --git a/dozorova_alena_lab_4/Publisher/Program.cs b/dozorova_alena_lab_4/Publisher/Program.cs new file mode 100644 index 0000000..f45f635 --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Program.cs @@ -0,0 +1,40 @@ +using Publisher; +using System.Text; + +var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost"; +var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user"; +var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password"; +var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn"; + +var sender = new Sender(rabbitHost, rabbitUsername, rabbitPassword); + +sender.AddExcange(rabbitExchange); + +var rnd = new Random(); + +while (true) +{ + StringBuilder sb = new(); + + var type = rnd.Next(); + switch (type%2) + { + case 0: + { + sb.Append($"Был запрошен отчет о данных под номером {rnd.Next(1000)}"); + break; + } + case 1: + { + sb.Append($"Был запрошен отчет об ошибках под номером {rnd.Next(1000)}"); + break; + } + } + + var text = sb.ToString(); + Console.WriteLine($"Было опубликовано сообщение: {text}"); + sender.PublishToExchange(rabbitExchange, text); + + await Task.Delay(1000); +} + diff --git a/dozorova_alena_lab_4/Publisher/Properties/launchSettings.json b/dozorova_alena_lab_4/Publisher/Properties/launchSettings.json new file mode 100644 index 0000000..c756d2e --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Publisher": { + "commandName": "Project" + }, + "Container (Dockerfile)": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/dozorova_alena_lab_4/Publisher/Publisher.csproj b/dozorova_alena_lab_4/Publisher/Publisher.csproj new file mode 100644 index 0000000..a04999b --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Publisher.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0 + enable + enable + Linux + . + + + + + + + + diff --git a/dozorova_alena_lab_4/Publisher/Publisher.csproj.user b/dozorova_alena_lab_4/Publisher/Publisher.csproj.user new file mode 100644 index 0000000..3139c26 --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Publisher.csproj.user @@ -0,0 +1,9 @@ + + + + Container (Dockerfile) + + + ProjectDebugger + + \ No newline at end of file diff --git a/dozorova_alena_lab_4/Publisher/Publisher.sln b/dozorova_alena_lab_4/Publisher/Publisher.sln new file mode 100644 index 0000000..3eb68d4 --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Publisher.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35004.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "Publisher.csproj", "{C23890FA-A4DD-4E5B-897F-37210C2F60CE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3BB20EB3-DE49-46CE-8C7A-D956E3DE90BC} + EndGlobalSection +EndGlobal diff --git a/dozorova_alena_lab_4/Publisher/Sender.cs b/dozorova_alena_lab_4/Publisher/Sender.cs new file mode 100644 index 0000000..c43eb72 --- /dev/null +++ b/dozorova_alena_lab_4/Publisher/Sender.cs @@ -0,0 +1,69 @@ +using RabbitMQ.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Publisher +{ + public class Sender : IDisposable + { + private readonly ConnectionFactory _connectionFactory; + private readonly IConnection _connection; + private readonly IModel _channel; + + public HashSet Exchanges { get; private set; } = new HashSet(); + + public Sender(string brockerHost, string brockerUsername, string brockerPassword) + { + _connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword }; + _connection = _connectionFactory.CreateConnection(); + _channel = _connection.CreateModel(); + } + + public bool AddExcange(string exchange, string exchangeType = ExchangeType.Fanout) + { + try + { + _channel.ExchangeDeclare(exchange, exchangeType); + Exchanges.Add(exchange); + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return false; + } + + public bool PublishToExchange(string exchange, string message) + { + try + { + if (!Exchanges.Contains(exchange)) + return false; + + var messageBody = Encoding.UTF8.GetBytes(message); + _channel.BasicPublish(exchange: exchange, + routingKey: string.Empty, + basicProperties: null, + body: messageBody); + return true; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return false; + } + + ~Sender() => Dispose(); + + public void Dispose() + { + _connection.Dispose(); + _channel.Dispose(); + } + } +} diff --git a/dozorova_alena_lab_4/README.md b/dozorova_alena_lab_4/README.md new file mode 100644 index 0000000..ed18814 --- /dev/null +++ b/dozorova_alena_lab_4/README.md @@ -0,0 +1,39 @@ +# Лабораторная работа 4 +В рамках данной работы были реализованы несколько проектов, работающих с RabbitMQ. +## tutorial +Для каждого урока были созданы консольные проекты +### "Hello World!" +![Task 1](image-4.png) +### Work Queues +![Task 2](image-5.png) +### Publish/Subscribe +![Task 3](image-6.png) +## Описание +В качестве предметной области была выбрана система запросов отчета двух видов: отчета и ошибок. +## Запуск +Для запуска лабораторной работы необходимо иметь запущенный Docker на устройстве. +Необходимо перейти в папку, где располагается данный файл. Далее открыть терминал и ввести команду: +``` +docker compose up -d --build +``` +Порты для RabbitMQ были 8081 (для UI) и 5672. +## Анализ +Первоначальный вариант запуска предполагает, что имеется всего 2 потребителя: + 1. Тратит на обработку сообщения 2-3 секунды + 2. Тратит на обработку сообщения крайне малое время +Задержка при обработке понижает пропускную способность обработчика, что вызывает переполнение очереди. Это подтверждается скринами. +
+![alt text](image.png) +
+![alt text](image-1.png) +
+Теперь запустим несколько обычных обработчиков. Очередь не переполнена постоянно, а периодически, соответственно обработчики вполне справляются с потоком сообщений и увеличение их количества позволит в принципе избавиться от переполнения +
+![alt text](image-2.png) +
+![alt text](image-3.png) + +## Видеодемонстрация +Демонстрация: (https://drive.google.com/file/d/16gJMGbMKSFZ_I5gCzuDekpAqUrhbpFRA/view?usp=sharing) Стоит обратить внимание на то, что настройки docker compose файла не гарантируют верный порядок подъема контейнеров, из-за чего некоторые контейнеры пришлось перезапустить. + + diff --git a/dozorova_alena_lab_4/Receive/Program.cs b/dozorova_alena_lab_4/Receive/Program.cs new file mode 100644 index 0000000..ffe992b --- /dev/null +++ b/dozorova_alena_lab_4/Receive/Program.cs @@ -0,0 +1,29 @@ +using System.Text; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.QueueDeclare(queue: "hello", + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + +Console.WriteLine(" [*] Waiting for messages."); + +var consumer = new EventingBasicConsumer(channel); +consumer.Received += (model, ea) => +{ + var body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); + Console.WriteLine($" [x] Received {message}"); +}; +channel.BasicConsume(queue: "hello", + autoAck: true, + consumer: consumer); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); \ No newline at end of file diff --git a/dozorova_alena_lab_4/Receive/Receive.csproj b/dozorova_alena_lab_4/Receive/Receive.csproj new file mode 100644 index 0000000..f72406b --- /dev/null +++ b/dozorova_alena_lab_4/Receive/Receive.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/ReceiveLogs/Program.cs b/dozorova_alena_lab_4/ReceiveLogs/Program.cs new file mode 100644 index 0000000..f1a8612 --- /dev/null +++ b/dozorova_alena_lab_4/ReceiveLogs/Program.cs @@ -0,0 +1,31 @@ +using System.Text; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout); + +// declare a server-named queue +var queueName = channel.QueueDeclare().QueueName; +channel.QueueBind(queue: queueName, + exchange: "logs", + routingKey: string.Empty); + +Console.WriteLine(" [*] Waiting for logs."); + +var consumer = new EventingBasicConsumer(channel); +consumer.Received += (model, ea) => +{ + byte[] body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); + Console.WriteLine($" [x] {message}"); +}; +channel.BasicConsume(queue: queueName, + autoAck: true, + consumer: consumer); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); \ No newline at end of file diff --git a/dozorova_alena_lab_4/ReceiveLogs/ReceiveLogs.csproj b/dozorova_alena_lab_4/ReceiveLogs/ReceiveLogs.csproj new file mode 100644 index 0000000..f72406b --- /dev/null +++ b/dozorova_alena_lab_4/ReceiveLogs/ReceiveLogs.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/Send/Program.cs b/dozorova_alena_lab_4/Send/Program.cs new file mode 100644 index 0000000..4e0f5c2 --- /dev/null +++ b/dozorova_alena_lab_4/Send/Program.cs @@ -0,0 +1,24 @@ +using System.Text; +using RabbitMQ.Client; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.QueueDeclare(queue: "hello", + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + +const string message = "Hello World!"; +var body = Encoding.UTF8.GetBytes(message); + +channel.BasicPublish(exchange: string.Empty, + routingKey: "hello", + basicProperties: null, + body: body); +Console.WriteLine($" [x] Sent {message}"); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); \ No newline at end of file diff --git a/dozorova_alena_lab_4/Send/Send.csproj b/dozorova_alena_lab_4/Send/Send.csproj new file mode 100644 index 0000000..f72406b --- /dev/null +++ b/dozorova_alena_lab_4/Send/Send.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/Worker/Program.cs b/dozorova_alena_lab_4/Worker/Program.cs new file mode 100644 index 0000000..d8b86be --- /dev/null +++ b/dozorova_alena_lab_4/Worker/Program.cs @@ -0,0 +1,39 @@ +using System.Text; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; + +var factory = new ConnectionFactory { HostName = "localhost" }; +using var connection = factory.CreateConnection(); +using var channel = connection.CreateModel(); + +channel.QueueDeclare(queue: "task_queue", + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + +channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false); + +Console.WriteLine(" [*] Waiting for messages."); + +var consumer = new EventingBasicConsumer(channel); +consumer.Received += (model, ea) => +{ + byte[] body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); + Console.WriteLine($" [x] Received {message}"); + + int dots = message.Split('.').Length - 1; + Thread.Sleep(dots * 1000); + + Console.WriteLine(" [x] Done"); + + // here channel could also be accessed as ((EventingBasicConsumer)sender).Model + channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); +}; +channel.BasicConsume(queue: "task_queue", + autoAck: false, + consumer: consumer); + +Console.WriteLine(" Press [enter] to exit."); +Console.ReadLine(); \ No newline at end of file diff --git a/dozorova_alena_lab_4/Worker/Worker.csproj b/dozorova_alena_lab_4/Worker/Worker.csproj new file mode 100644 index 0000000..f72406b --- /dev/null +++ b/dozorova_alena_lab_4/Worker/Worker.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/dozorova_alena_lab_4/docker-compose.yaml b/dozorova_alena_lab_4/docker-compose.yaml new file mode 100644 index 0000000..5e13516 --- /dev/null +++ b/dozorova_alena_lab_4/docker-compose.yaml @@ -0,0 +1,59 @@ +services: + rabbit: + image: rabbitmq:3.10.7-management + restart: always + ports: + - 5672:5672 + - 8081:15672 + environment: + RABBITMQ_DEFAULT_USER: admin + RABBITMQ_DEFAULT_PASS: admin + + publisher: + build: ./Publisher/ + restart: always + depends_on: + - rabbit + environment: + RABBIT_HOST: rabbit + RABBIT_USERNAME: admin + RABBIT_PASSWORD: admin + RABBIT_EXCHANGE: 'ReportIn' + + concumer1: + build: ./ConsumerSimple/ + restart: always + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_USERNAME: admin + RABBIT_PASSWORD: admin + RABBIT_EXCHANGE: 'ReportIn' + RABBIT_QUEUE: 'First' + + concumer2: + build: ./ConsumerSimple/ + restart: always + depends_on: + - rabbit + - publisher + environment: + RABBIT_HOST: rabbit + RABBIT_USERNAME: admin + RABBIT_PASSWORD: admin + RABBIT_EXCHANGE: 'ReportIn' + RABBIT_QUEUE: 'Second' + # concumer2: + # build: ./ConsumerDelay/ + # restart: always + # depends_on: + # - rabbit + # - publisher + # environment: + # RABBIT_HOST: rabbit + # RABBIT_USERNAME: admin + # RABBIT_PASSWORD: admin + # RABBIT_EXCHANGE: 'ReportIn' + # RABBIT_QUEUE: 'Second' diff --git a/dozorova_alena_lab_4/image-1.png b/dozorova_alena_lab_4/image-1.png new file mode 100644 index 0000000..ae1379f Binary files /dev/null and b/dozorova_alena_lab_4/image-1.png differ diff --git a/dozorova_alena_lab_4/image-2.png b/dozorova_alena_lab_4/image-2.png new file mode 100644 index 0000000..6b459d5 Binary files /dev/null and b/dozorova_alena_lab_4/image-2.png differ diff --git a/dozorova_alena_lab_4/image-3.png b/dozorova_alena_lab_4/image-3.png new file mode 100644 index 0000000..cb4ffc7 Binary files /dev/null and b/dozorova_alena_lab_4/image-3.png differ diff --git a/dozorova_alena_lab_4/image-4.png b/dozorova_alena_lab_4/image-4.png new file mode 100644 index 0000000..09c1d5e Binary files /dev/null and b/dozorova_alena_lab_4/image-4.png differ diff --git a/dozorova_alena_lab_4/image-5.png b/dozorova_alena_lab_4/image-5.png new file mode 100644 index 0000000..5a7333d Binary files /dev/null and b/dozorova_alena_lab_4/image-5.png differ diff --git a/dozorova_alena_lab_4/image-6.png b/dozorova_alena_lab_4/image-6.png new file mode 100644 index 0000000..a2f8b70 Binary files /dev/null and b/dozorova_alena_lab_4/image-6.png differ diff --git a/dozorova_alena_lab_4/image.png b/dozorova_alena_lab_4/image.png new file mode 100644 index 0000000..afe250e Binary files /dev/null and b/dozorova_alena_lab_4/image.png differ diff --git a/dozorova_alena_lab_5/.gitignore b/dozorova_alena_lab_5/.gitignore index 30c9ddf..0d65e88 100644 --- a/dozorova_alena_lab_5/.gitignore +++ b/dozorova_alena_lab_5/.gitignore @@ -10,3 +10,29 @@ /dozorova_alena_lab_5/ConsoleApp1/.vs /dozorova_alena_lab_5/ConsoleApp1/bin /dozorova_alena_lab_5/ConsoleApp1/obj +/dozorova_alena_lab_3/PostService/.vs +/dozorova_alena_lab_3/WorkerService/.vs +/dozorova_alena_lab_4/Receive/bin +/dozorova_alena_lab_4/Receive/obj +/dozorova_alena_lab_4/Send/bin +/dozorova_alena_lab_4/Send/obj +/dozorova_alena_lab_4/EmitLog/.vs +/dozorova_alena_lab_4/EmitLog/obj +/dozorova_alena_lab_4/NewTask/.vs +/dozorova_alena_lab_4/NewTask/bin +/dozorova_alena_lab_4/NewTask/obj +/dozorova_alena_lab_4/ReceiveLogs/obj +/dozorova_alena_lab_4/Worker/.vs +/dozorova_alena_lab_4/Worker/bin +/dozorova_alena_lab_4/Worker/obj +/dozorova_alena_lab_4/EmitLog/bin +/dozorova_alena_lab_4/ReceiveLogs/.vs +/dozorova_alena_lab_4/ReceiveLogs/bin +/dozorova_alena_lab_4/ConsumerDelay/.vs +/dozorova_alena_lab_4/ConsumerDelay/obj +/dozorova_alena_lab_4/ConsumerDelay/Properties +/dozorova_alena_lab_4/ConsumerSimple/.vs +/dozorova_alena_lab_4/ConsumerSimple/obj +/dozorova_alena_lab_4/Publisher/.vs +/dozorova_alena_lab_4/Publisher/bin +/dozorova_alena_lab_4/Publisher/objs diff --git a/kalyshev_yan_lab_2/.gitignore b/kalyshev_yan_lab_2/.gitignore new file mode 100644 index 0000000..e1c443e --- /dev/null +++ b/kalyshev_yan_lab_2/.gitignore @@ -0,0 +1,5 @@ +data/ +result/ +result_first/ +result_second/ +datagen.py diff --git a/kalyshev_yan_lab_2/FirstProgram/Dockerfile b/kalyshev_yan_lab_2/FirstProgram/Dockerfile new file mode 100644 index 0000000..79fedcb --- /dev/null +++ b/kalyshev_yan_lab_2/FirstProgram/Dockerfile @@ -0,0 +1,16 @@ +#Берем базовый образ python +FROM python:3.12 + +#Устанавливаем рабочую директорию +WORKDIR /app + +#Копирум код в рабочую директорию +COPY main.py . + +#Задаем /var/data как монтируемый +VOLUME ["/var/data"] +#Задаем /var/result как монтируемый +VOLUME ["/var/result"] + +#Задаем команду для выполнения программы +CMD ["python", "main.py"] diff --git a/kalyshev_yan_lab_2/FirstProgram/main.py b/kalyshev_yan_lab_2/FirstProgram/main.py new file mode 100644 index 0000000..8f9edf1 --- /dev/null +++ b/kalyshev_yan_lab_2/FirstProgram/main.py @@ -0,0 +1,79 @@ +import os +import random + +# Установите полный путь к каталогу, в котором нужно искать самый большой файл. +CATALOG_PATH = "/var/data" + +# Полный путь до файла результата. +RESULT_FILE = "/var/result/data.txt" + + +def find_largest_file(directory): + """Ищет самый большой по объему файл в заданном каталоге и его подкаталогах.""" + + largest_file = None + max_size = 0 + + for root, _, files in os.walk(directory): + for file in files: + # Полный путь к текущему файлу. + filepath = os.path.join(root, file) + + try: + file_size = os.stat(filepath).st_size + + if file_size > max_size: + max_size = file_size + largest_file = (filepath, file_size) + + except OSError as e: + print(f"Ошибка при открытии файла '{filepath}': {e}") + + return largest_file + + +def copy_file(src, dst): + """Копирует содержимое файла src в файл dst.""" + + try: + with open(dst, "wb") as f_dst, open(src, "rb") as f_src: + while chunk := f_src.read(4096): + f_dst.write(chunk) + + print(f"Файл '{src}' успешно скопирован в '{dst}'.") + + except Exception as e: + print(f"Ошибка при копировании файла '{src}': {e}") + + +def main(): + largest_file_path = find_largest_file(CATALOG_PATH) + + if largest_file_path: + src_path, _ = largest_file_path + dst_path = RESULT_FILE + + copy_file(src_path, dst_path) + + else: + print("Нет файлов в каталоге.") + + +def generate_random_numbers(filename, count): + """Функция генерирует случайные числа и записывает их в файл.""" + + with open(filename, "w") as f: + for _ in range(count): + num = random.randint(0, 1000) + f.write(str(num) + "\n") + + print(f"Случайные числа успешно записаны в '{filename}'.") + + +if __name__ == "__main__": + generate_random_numbers("/var/data/data1.txt", 50) + generate_random_numbers("/var/data/data2.txt", 75) + generate_random_numbers("/var/data/data3.txt", 25) + print("Генерация файлов завершена.") + + main() diff --git a/kalyshev_yan_lab_2/README.md b/kalyshev_yan_lab_2/README.md new file mode 100644 index 0000000..8114ef3 --- /dev/null +++ b/kalyshev_yan_lab_2/README.md @@ -0,0 +1,74 @@ +# Калышев Ян ПИбд-42 + +## Описание + +Этот проект предоставляет 2 контейнера с простыми python-скриптами такими, что результат первого является исходными данными для второго. + +## 1. Варианты + +Для первой программы был взят вариант: +**0**. Ищет в каталоге /var/data самый большой по объёму файл и перекладывает его в /var/result/data.txt. + +Для второй программы был взят вариант: +**2**. Ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt. + +## 2. Структура Dockerfile + +Оба Dockerfile почти одинаковые: + +```Dockerfile +#Берем базовый образ python +FROM python:3.12 + +#Устанавливаем рабочую директорию +WORKDIR /app + +#Копирум код в рабочую директорию +COPY main.py . + +#Задаем /var/data как монтируемый +VOLUME ["/var/data"] +#Задаем /var/result как монтируемый +VOLUME ["/var/result"] + +#Задаем команду для выполнения программы +CMD ["python", "main.py"] +``` + +## 3. Docker Compose + +`docker-compose.yml`: + +```yaml +services: + #Первый скрипт + first: + #Указание директории для сборки первого скрипта + build: ./FirstProgram/ + #Монтирование 2 каталогов из хост системы + volumes: + - ./data:/var/data + - ./result_first:/var/result + + #Второй скрипт + second: + #Указание директории для сборки второго скрипта + build: ./SecondProgram/ + #Задание очередности запуска с помощью depends_on + depends_on: + - first + #Монтирование 2 каталогов из хост системы + volumes: + - ./result_first:/var/data + - ./result_second:/var/result +``` + +## 4. Запуск + +Для запуска использовать команду `docker compose up --build` +Предварительно нужно создать папку `data`, в которой создать файлы, где каждая строка - это число. +Результат первого скрипта будет в папке `result_first`, результат второго скрипта будет в папке `result_second`. + +## 7. Ссылка на видео + +[Видео-отчёт Калышев Ян ПИбд-42](https://zyzf.space/s/65HRyTTXAzxpwBF) diff --git a/kalyshev_yan_lab_2/SecondProgram/Dockerfile b/kalyshev_yan_lab_2/SecondProgram/Dockerfile new file mode 100644 index 0000000..79fedcb --- /dev/null +++ b/kalyshev_yan_lab_2/SecondProgram/Dockerfile @@ -0,0 +1,16 @@ +#Берем базовый образ python +FROM python:3.12 + +#Устанавливаем рабочую директорию +WORKDIR /app + +#Копирум код в рабочую директорию +COPY main.py . + +#Задаем /var/data как монтируемый +VOLUME ["/var/data"] +#Задаем /var/result как монтируемый +VOLUME ["/var/result"] + +#Задаем команду для выполнения программы +CMD ["python", "main.py"] diff --git a/kalyshev_yan_lab_2/SecondProgram/main.py b/kalyshev_yan_lab_2/SecondProgram/main.py new file mode 100644 index 0000000..607ae04 --- /dev/null +++ b/kalyshev_yan_lab_2/SecondProgram/main.py @@ -0,0 +1,60 @@ +# Установите полный путь к файлу, из которого нужно читать числа. +DATA_FILE = "/var/data/data.txt" + +# Полный путь до файла результата. +RESULT_FILE = "/var/result/result.txt" + + +def find_smallest_number(data_file): + """Ищет наименьшее число в заданном файле.""" + + try: + with open(data_file, "r") as f: + numbers = [int(line.strip()) for line in f.readlines()] + + smallest_num = min(numbers) + return smallest_num + + except ValueError as e: + print(f"Ошибка при преобразовании строк в числа: {e}") + + except Exception as e: + print(f"Ошибка чтения файла '{data_file}': {e}") + + return None + + +def cube_number(num): + """Возвращает куб заданного числа.""" + + return num**3 + + +def write_result(result_file, result): + """Записывает результат в файл.""" + + try: + with open(result_file, "w") as f: + f.write(str(result)) + + print(f"Результат '{result}' успешно записан в '{result_file}'.") + + except Exception as e: + print(f"Ошибка записи результата в файл '{result_file}': {e}") + + +def main(): + smallest_num = find_smallest_number(DATA_FILE) + + if smallest_num is not None: + result = cube_number(smallest_num) + + write_result(RESULT_FILE, result) + print(result) + + else: + print("Нет чисел в файле.") + + +if __name__ == "__main__": + main() diff --git a/kalyshev_yan_lab_2/docker-compose.yml b/kalyshev_yan_lab_2/docker-compose.yml new file mode 100644 index 0000000..76eb9f7 --- /dev/null +++ b/kalyshev_yan_lab_2/docker-compose.yml @@ -0,0 +1,21 @@ +services: + #Первый скрипт + first: + #Указание директории для сборки первого скрипта + build: ./FirstProgram/ + #Монтирование 2 каталогов из хост системы + volumes: + - ./data:/var/data + - ./result_first:/var/result + + #Второй скрипт + second: + #Указание директории для сборки второго скрипта + build: ./SecondProgram/ + #Задание очередности запуска с помощью depends_on + depends_on: + - first + #Монтирование 2 каталогов из хост системы + volumes: + - ./result_first:/var/data + - ./result_second:/var/result diff --git a/kuzarin_maxim_lab_5/.gitignore b/kuzarin_maxim_lab_5/.gitignore new file mode 100644 index 0000000..104b544 --- /dev/null +++ b/kuzarin_maxim_lab_5/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/kuzarin_maxim_lab_5/Images/Resouts.png b/kuzarin_maxim_lab_5/Images/Resouts.png new file mode 100644 index 0000000..55ce812 Binary files /dev/null and b/kuzarin_maxim_lab_5/Images/Resouts.png differ diff --git a/kuzarin_maxim_lab_5/MatrixMultiplication.sln b/kuzarin_maxim_lab_5/MatrixMultiplication.sln new file mode 100644 index 0000000..7b9b107 --- /dev/null +++ b/kuzarin_maxim_lab_5/MatrixMultiplication.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.34916.146 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixMultiplication", "MatrixMultiplication\MatrixMultiplication.csproj", "{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {619485C2-FE35-496B-9E25-4F5465D0C1A1} + EndGlobalSection +EndGlobal diff --git a/kuzarin_maxim_lab_5/MatrixMultiplication/MatrixMultiplication.csproj b/kuzarin_maxim_lab_5/MatrixMultiplication/MatrixMultiplication.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/kuzarin_maxim_lab_5/MatrixMultiplication/MatrixMultiplication.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/kuzarin_maxim_lab_5/MatrixMultiplication/Program.cs b/kuzarin_maxim_lab_5/MatrixMultiplication/Program.cs new file mode 100644 index 0000000..2a5dc76 --- /dev/null +++ b/kuzarin_maxim_lab_5/MatrixMultiplication/Program.cs @@ -0,0 +1,117 @@ + +using System.Diagnostics; +internal class Program +{ + private static string[] _resTableColumnsNames = new string[] { "m*m", "1 t", "2 t", "3 t", "4 t", "5 t", "6 t", "7 t", "8 t" }; + + private static void Main(string[] args) + { + Console.WriteLine(string.Join("\t", _resTableColumnsNames)); + + for (int i = 10; i < 10000; i *= 2) + { + var a = CreateMatrix(i, i); + var b = CreateMatrix(i, i); + + List times = new() { i }; + + for (int j = 1; j <= 8; j++) + { + var sw = new Stopwatch(); + sw.Start(); + + MultiplyMatrix(a, b, j); + + sw.Stop(); + times.Add(sw.ElapsedMilliseconds); + } + Console.WriteLine(string.Join("\t", times)); + } + } + + /// + /// Создаём матрицу случайных элементов + /// + /// + /// + /// + private static int[,] CreateMatrix(int x, int y) + { + var rnd = new Random(); + + var res = new int[y, x]; + + for (int i = 0; i < y; i++) + { + for (int j = 0; j < x; j++) + { + res[i, j] = rnd.Next(0, 100); + } + } + return res; + } + + /// + /// Вывести матрицу. Использовался при отладке + /// + /// + private static void PrintMatrix(int[,] mx) + { + for (int i = 0; i < mx.GetLength(0); i++) + { + for (int j = 0; j < mx.GetLength(1); j++) + { + Console.Write($"{mx[i, j].ToString("000")}\t"); + } + Console.WriteLine(); + } + } + + /// + /// Непосредственно умножение матриц + /// + /// + /// + /// + /// + private static int[,] MultiplyMatrix(int[,] a, int[,] b, int maxTask) + { + int[,] res = new int[a.GetLength(0), b.GetLength(1)]; + + var semaphore = new SemaphoreSlim(maxTask, maxTask); + + for (int i = 0; i < a.GetLength(0); i++) + { + for (int j = 0; j < b.GetLength(1); j++) + { + semaphore.Wait(); + int ci = i; + int cj = j; + _ = Task.Run(() => + { + try + { + res[ci, cj] = CalculateElement(a, b, ci, cj); + } + finally + { + semaphore.Release(); + } + }); + } + } + semaphore.Wait(maxTask); + return res; + } + + /// + /// Вычисление значение одного элемента + /// + /// + /// + /// + /// + /// + private static int CalculateElement(int[,] a, int[,] b, int i, int j) + => Enumerable.Range(0, a.GetLength(1)).Sum(k => a[i, k] * b[k, j]); +} \ No newline at end of file diff --git a/kuzarin_maxim_lab_5/README.md b/kuzarin_maxim_lab_5/README.md new file mode 100644 index 0000000..0fb394a --- /dev/null +++ b/kuzarin_maxim_lab_5/README.md @@ -0,0 +1,20 @@ +# Лабораторная работа 5 +Данная работа посвящена параллельному умножению больших матриц (чтобы это был побыстрее) +## Описание +Основной принцип умножения матриц: строки умножаются на столбцы, таким образом получаются элементы. И так как значения в строках/столбцах не меняется по ходу алгоритма, его достаточно легко можно распаралелить. + +## Запуск +Приложение представлет собой консольную программу на C#, которую можно скомпилировать и затем запустит exe файл. В результате в окне консоли появится таблица сравнения времени умножения 2-х квадратных матриц (размер указан в первой колонке) с использованием разного числа потоков(от 1 до 8). Чем больше размер, тем дольше будет идти расчёт. +## Результаты +Результаты одного из запусков программы представлены ниже. +
+![Resout](Images/Resouts.png) +
+Как можно заметить, на небольших размерах распаралеливание не приносит никакого выигрыша, а иногда даже удлиняет время работы. Это связана с тем, что работы с потоками (запуск, получение результата и т. п.) - требует дополнительного времени, а из-за малого числа операций в целом, получаем не прирост производительности, а её падение. +Противоположно обстоят дела в случае с большими матрицами. Так как там расчётов значительно больше, распаралеливание начинает значительно ускорять вычисление результата. Причём, часто можно видеть, что, например, увеличения числа потоков с 1 до 2 (в 2 раза) сокращает время в 2 раза. Но чем больше потоков, тем прирост меньше (так как вновь вступают в силу факторы, описанные ранее). И прирост производительности пусть и есть, но он очень небольшой. + +## Видеодемонстрация +Был записан видеоролик, демонстрирующий процесс запуска и работы системы. Он расположен по [адресу](https://drive.google.com/file/d/1dhA3JUAhhpDUh32xVW7jMuW1BKDX02eV/view?usp=sharing) + + + diff --git a/yakovleva_yulia_lab_3/Administrator/.config/dotnet-tools.json b/yakovleva_yulia_lab_3/Administrator/.config/dotnet-tools.json new file mode 100644 index 0000000..d7000af --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.8", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/Administrator/.dockerignore b/yakovleva_yulia_lab_3/Administrator/.dockerignore new file mode 100644 index 0000000..4d72b4f --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/Administrator/.gitignore b/yakovleva_yulia_lab_3/Administrator/.gitignore new file mode 100644 index 0000000..5e57f18 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator.sln b/yakovleva_yulia_lab_3/Administrator/Administrator.sln new file mode 100644 index 0000000..4bdb397 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Administrator", "Administrator\Administrator.csproj", "{45DF535F-4F9E-4A5C-9D60-4B0709863ED8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {45DF535F-4F9E-4A5C-9D60-4B0709863ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45DF535F-4F9E-4A5C-9D60-4B0709863ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45DF535F-4F9E-4A5C-9D60-4B0709863ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45DF535F-4F9E-4A5C-9D60-4B0709863ED8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {211037E3-7DB9-4964-B9B8-211487849EED} + EndGlobalSection +EndGlobal diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.csproj b/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.csproj new file mode 100644 index 0000000..3583898 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + b3476a56-c45e-4a63-be32-5987c93f46b1 + Linux + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.http b/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.http new file mode 100644 index 0000000..6780d1b --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Administrator.http @@ -0,0 +1,6 @@ +@Administrator_HostAddress = http://localhost:5015 + +GET {{Administrator_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Controllers/AdminController.cs b/yakovleva_yulia_lab_3/Administrator/Administrator/Controllers/AdminController.cs new file mode 100644 index 0000000..1357898 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Controllers/AdminController.cs @@ -0,0 +1,126 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Administrator.DataBase; +using Administrator.DataBase.DBModels; + +namespace Administrator.Controllers +{ + [ApiController] + [Route("Administrators/")] + public class AdminController : ControllerBase + { + private readonly AdminDataBaseContext _context; + private readonly ILogger _logger; + private readonly IHttpClientFactory _clientFactory; + + public AdminController(AdminDataBaseContext context, ILogger logger, IHttpClientFactory clientFactory) + { + _context = context; + _logger = logger; + _clientFactory = clientFactory; + } + + // + [HttpPost] + public async Task> CreateAdministrator(Admin administrator) + { + if (!await ClientExists(administrator.ClientId)) + { + return BadRequest(" ."); + } + + _context.Administrators.Add(administrator); + await _context.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetAdministratorById), new { id = administrator.Id }, administrator); + } + + // + [HttpPut("{id}")] + public async Task UpdateAdministrator(int id, Admin updatedAdministrator) + { + if (!await ClientExists(updatedAdministrator.ClientId)) + { + return BadRequest(" ."); + } + + if (id != updatedAdministrator.Id) + { + return BadRequest(); + } + + _context.Entry(updatedAdministrator).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!AdminExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // + [HttpDelete("{id}")] + public async Task DeleteAdministrator(int id) + { + var administrator = await _context.Administrators.FindAsync(id); + if (administrator == null) + { + return NotFound(" "); + } + + _context.Administrators.Remove(administrator); + await _context.SaveChangesAsync(); + + return NoContent(); + } + + // + [HttpGet] + public async Task>> GetAllAdministrators() + { + return await _context.Administrators.ToListAsync(); + } + + // ID + [HttpGet("{id}")] + public async Task> GetAdministratorById(int id) + { + var administrator = await _context.Administrators.FindAsync(id); + + if (administrator == null) + { + return NotFound(" "); + } + + return administrator; + } + + private bool AdminExists(int id) + { + return _context.Administrators.Any(e => e.Id == id); + } + + private async Task ClientExists(int buyerId) + { + var client = _clientFactory.CreateClient("BuyerService"); + var response = await client.GetAsync($"Buyers/{buyerId}"); + return response.IsSuccessStatusCode; + } + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/AdminDataBaseContext.cs b/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/AdminDataBaseContext.cs new file mode 100644 index 0000000..b66251b --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/AdminDataBaseContext.cs @@ -0,0 +1,20 @@ +using Administrator.DataBase.DBModels; +using Microsoft.EntityFrameworkCore; + +namespace Administrator.DataBase +{ + public class AdminDataBaseContext : DbContext + { + public AdminDataBaseContext(DbContextOptions options) + : base(options) + { + } + + public DbSet Administrators { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("Administrators"); + } + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/DBModels/Admin.cs b/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/DBModels/Admin.cs new file mode 100644 index 0000000..4879311 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/DataBase/DBModels/Admin.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace Administrator.DataBase.DBModels +{ + public class Admin + { + [Key] + public int Id { get; set; } + + [Required] + [StringLength(50)] + public string FirstName { get; set; } + + + [StringLength(50)] + public string SecondName { get; set; } + + [Required] + public int ClientId { get; set; } + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Dockerfile b/yakovleva_yulia_lab_3/Administrator/Administrator/Dockerfile new file mode 100644 index 0000000..a9d7d88 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Dockerfile @@ -0,0 +1,25 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Administrator/Administrator.csproj", "Administrator/"] +RUN dotnet restore "./Administrator/Administrator.csproj" +COPY . . +WORKDIR "/src/Administrator" +RUN dotnet build "./Administrator.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Administrator.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Administrator.dll"] \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Program.cs b/yakovleva_yulia_lab_3/Administrator/Administrator/Program.cs new file mode 100644 index 0000000..56b8d8b --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Program.cs @@ -0,0 +1,10 @@ +var host = CreateHostBuilder(args).Build(); + +host.Run(); + +static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Properties/launchSettings.json b/yakovleva_yulia_lab_3/Administrator/Administrator/Properties/launchSettings.json new file mode 100644 index 0000000..78fbb4e --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Properties/launchSettings.json @@ -0,0 +1,42 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5015" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "http://+:80" + }, + "publishAllPorts": true, + "useSSL": false + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60492", + "sslPort": 0 + } + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/Startup.cs b/yakovleva_yulia_lab_3/Administrator/Administrator/Startup.cs new file mode 100644 index 0000000..adec894 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/Startup.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using Administrator.DataBase; + +public class Startup +{ + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + + services.AddDbContext(options => + options.UseNpgsql(Configuration.GetConnectionString("AdminDatabase"))); + + services.AddHttpClient("BuyerService", client => + { + client.BaseAddress = new Uri("http://buyer-service:8080/"); + }); + + services.AddSwaggerGen(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceScopeFactory serviceScopeFactory) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthorization(); + + using (var scope = serviceScopeFactory.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + context.Database.Migrate(); + } + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + app.UseSwagger(); + app.UseSwaggerUI(); + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.Development.json b/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.json b/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.json new file mode 100644 index 0000000..cf4c47d --- /dev/null +++ b/yakovleva_yulia_lab_3/Administrator/Administrator/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "AdminDatabase": "Host=postgresdb;Database=administrator;Username=postgres;Password=123" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/yakovleva_yulia_lab_3/Buyer/.dockerignore b/yakovleva_yulia_lab_3/Buyer/.dockerignore new file mode 100644 index 0000000..4d72b4f --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/Buyer/.gitignore b/yakovleva_yulia_lab_3/Buyer/.gitignore new file mode 100644 index 0000000..5e57f18 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer.sln b/yakovleva_yulia_lab_3/Buyer/Buyer.sln new file mode 100644 index 0000000..73c139c --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Buyer", "Buyer\Buyer.csproj", "{3845B5A1-0A3C-427B-9659-67590EEDB4B6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3845B5A1-0A3C-427B-9659-67590EEDB4B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3845B5A1-0A3C-427B-9659-67590EEDB4B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3845B5A1-0A3C-427B-9659-67590EEDB4B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3845B5A1-0A3C-427B-9659-67590EEDB4B6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2074E7E7-D084-4F69-AED8-8DD2830D2A68} + EndGlobalSection +EndGlobal diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer - Backup.csproj b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer - Backup.csproj new file mode 100644 index 0000000..3583898 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer - Backup.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + b3476a56-c45e-4a63-be32-5987c93f46b1 + Linux + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.csproj b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.csproj new file mode 100644 index 0000000..7eb035b --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + f9482e07-2725-46f1-9b04-c34d26c4f674 + Linux + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.http b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.http new file mode 100644 index 0000000..6780d1b --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Buyer.http @@ -0,0 +1,6 @@ +@Administrator_HostAddress = http://localhost:5015 + +GET {{Administrator_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Controllers/BuyerController.cs b/yakovleva_yulia_lab_3/Buyer/Buyer/Controllers/BuyerController.cs new file mode 100644 index 0000000..9f70376 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Controllers/BuyerController.cs @@ -0,0 +1,105 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Buyer.DataBase; +using Buyer.DataBase.DBModels; + +namespace Buyer.Controllers +{ + [ApiController] + [Route("Buyers/")] + public class BuyerController : Controller + { + private readonly BuyerDataBaseContext _dbContext; + + public BuyerController(BuyerDataBaseContext dbContext) + { + _dbContext = dbContext; + } + + // + [HttpGet] + public async Task>> GetAllBuyers() + { + return await _dbContext.Buyers.ToListAsync(); + } + + // ID + [HttpGet("{id}")] + public async Task> GetBuyer(int id) + { + var Buyer = await _dbContext.Buyers.FindAsync(id); + + if (Buyer == null) + { + return NotFound(); + } + + return Buyer; + } + + // + [HttpPost] + public async Task> CreateBuyer(Buyers Buyer) + { + _dbContext.Buyers.Add(Buyer); + await _dbContext.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetBuyer), new { id = Buyer.Id }, Buyer); + } + + // + [HttpPut("{id}")] + public async Task UpdateBuyer(int id, Buyers Buyer) + { + if (id != Buyer.Id) + { + return BadRequest(); + } + + _dbContext.Entry(Buyer).State = EntityState.Modified; + + try + { + await _dbContext.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!BuyerExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // + [HttpDelete("{id}")] + public async Task DeleteBuyer(int id) + { + var Buyer = await _dbContext.Buyers.FindAsync(id); + if (Buyer == null) + { + return NotFound(); + } + + _dbContext.Buyers.Remove(Buyer); + await _dbContext.SaveChangesAsync(); + + return NoContent(); + } + + private bool BuyerExists(int id) + { + return _dbContext.Buyers.Any(e => e.Id == id); + } + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/BuyerDataBaseContext.cs b/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/BuyerDataBaseContext.cs new file mode 100644 index 0000000..d645634 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/BuyerDataBaseContext.cs @@ -0,0 +1,20 @@ +using Buyer.DataBase.DBModels; +using Microsoft.EntityFrameworkCore; + +namespace Buyer.DataBase +{ + public class BuyerDataBaseContext : DbContext + { + public BuyerDataBaseContext(DbContextOptions options) + : base(options) + { + } + + public DbSet Buyers { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("Buyers"); + } + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/DBModels/Buyers.cs b/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/DBModels/Buyers.cs new file mode 100644 index 0000000..b7852c6 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/DataBase/DBModels/Buyers.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace Buyer.DataBase.DBModels +{ + public class Buyers + { + [Key] + public int Id { get; set; } + + [Required] + [StringLength(50)] + public string FirstName { get; set; } + + + [StringLength(50)] + public string SecondName { get; set; } + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Dockerfile b/yakovleva_yulia_lab_3/Buyer/Buyer/Dockerfile new file mode 100644 index 0000000..045b57a --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Dockerfile @@ -0,0 +1,27 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Buyer/Buyer.csproj", "Buyer/"] +RUN dotnet restore "./Buyer/Buyer.csproj" +COPY . . +WORKDIR "/src/Buyer" +RUN dotnet build "./Buyer.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Buyer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Buyer.dll"] + +CMD dotnet ef database update --no-build && dotnet BuyerService.dll \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Program.cs b/yakovleva_yulia_lab_3/Buyer/Buyer/Program.cs new file mode 100644 index 0000000..56b8d8b --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Program.cs @@ -0,0 +1,10 @@ +var host = CreateHostBuilder(args).Build(); + +host.Run(); + +static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Properties/launchSettings.json b/yakovleva_yulia_lab_3/Buyer/Buyer/Properties/launchSettings.json new file mode 100644 index 0000000..78fbb4e --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Properties/launchSettings.json @@ -0,0 +1,42 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5015" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "http://+:80" + }, + "publishAllPorts": true, + "useSSL": false + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60492", + "sslPort": 0 + } + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/Startup.cs b/yakovleva_yulia_lab_3/Buyer/Buyer/Startup.cs new file mode 100644 index 0000000..617d2d2 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/Startup.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore; +using Buyer.DataBase; + +public class Startup +{ + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + + services.AddDbContext(options => + options.UseNpgsql(Configuration.GetConnectionString("BuyerDatabase"))); + + services.AddSwaggerGen(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceScopeFactory serviceScopeFactory) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthorization(); + + using (var scope = serviceScopeFactory.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + context.Database.Migrate(); + } + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + app.UseSwagger(); + app.UseSwaggerUI(); + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.Development.json b/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.json b/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.json new file mode 100644 index 0000000..a2752bb --- /dev/null +++ b/yakovleva_yulia_lab_3/Buyer/Buyer/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "BuyerDatabase": "Host=postgresdb;Database=buyer;Username=postgres;Password=123" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/yakovleva_yulia_lab_3/README.md b/yakovleva_yulia_lab_3/README.md new file mode 100644 index 0000000..4092d9a --- /dev/null +++ b/yakovleva_yulia_lab_3/README.md @@ -0,0 +1,45 @@ +# Лабораторная работа 3 - REST API, Gateway и синхронный обмен между микросервисами + +## Описание +Были разработаны два микросервиса с простыми CRUD операциями и реализован синхронный обмен сообщениями между ними. + +Тема дипломной работы: Разработка системы для автоматизации процессов управления компьютерным клубом на платформе .Net + +На основе темы были созданны сущности: + +Администратор: +- Идентификатор +- Имя +- Фамилия +- Идентификатор клиента (связь "один ко многим") + +Клиент: +- Идентификатор +- Имя +- Фамилия + +Сервис Аминистратора имеет возможность управлять списком Клиентов. При создании Администратора можно указать идентификатор Клиента, +после чего идет запрос на сервис Клиента с целью узнать существует ли привязываемый Клиент. реализовано с помощью Web-API, интерфейс Swagger, +база данных PostgreSQL. Каждый сервис использует свою базу данных. + +## Запуск + +1. Запустить Docker +2. Открыть консоль, перейти в папку, где хранится docker-compose.yml +3. Выполнить команду: +``` +docker compose up --build +``` + +## Результат +Выполняем команду: +``` +docker compose ps +``` +Видим, что контейнеры успешно подняты. +Заходим на http://localhost:32774/swagger/index.html и http://localhost:32773/swagger/index.html - создаем администраторов и клиентов через Swagger. +Видим, что клиенты успешно созданны. +Создаем администраторов с ссылкой на клиента. + +## Отчет +Работоспособность: [видео](https://vk.com/video372869030_456239953?list=ln-KBJP1uxkWkQNlqzohl) \ No newline at end of file diff --git a/yakovleva_yulia_lab_3/docker-compose.yaml b/yakovleva_yulia_lab_3/docker-compose.yaml new file mode 100644 index 0000000..70475f6 --- /dev/null +++ b/yakovleva_yulia_lab_3/docker-compose.yaml @@ -0,0 +1,50 @@ +services: + postgresdb: + image: postgres:latest + container_name: postgres_container + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: 123 + POSTGRES_DB: administrator + PGDATA: /var/lib/postgresql/data/pgdata + ports: + - "5430:5432" # Проброс порта для PostgreSQL + volumes: + - ./database.sql:/docker-entrypoint-initdb.d/database.sql # Инициализация базы данных + restart: always + networks: + - desision-making-system-network + + administrator-service: + container_name: administrator-service + depends_on: + - postgresdb # Заивисмость от запуска Posgresql + build: + context: ./Administrator + dockerfile: ./Administrator/Dockerfile + environment: + ASPNETCORE_ENVIRONMENT: "Development" # Настраиваем среду разработки + ASPNETCORE_URLS: "http://+:8080" + ports: + - "32773:8080" # Проброс порта 8080 + networks: + - desision-making-system-network + + buyer-service: + container_name: buyer-service + depends_on: + - postgresdb # Заивисмость от запуска Posgresql + build: + context: ./Buyer + dockerfile: ./Buyer/Dockerfile + environment: + ASPNETCORE_ENVIRONMENT: "Development" # Настраиваем среду разработки + ASPNETCORE_URLS: "http://+:8080" + ports: + - "32774:8080" # Проброс порта + networks: + - desision-making-system-network + +networks: + desision-making-system-network: + driver: bridge