diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 000000000..3ba0c8259 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,40 @@ +# Deployment + +The recommended way to deploy OpenMU is through Docker. Depending on the scale you need, we provide multiple ways to do that. + +This describes a deployment of a test environment. A production environment might need additional steps, such as adding a ssl certificate to nginx. + +## All-in-one + +The [all-in-one deployment](/all-in-one/) is recommended, if you want to host on a small machine with a low amount of players. +In this case, all kinds of OpenMU subsystems (ConnectServer, GameServer, LoginServer, AdminPanel, ...) are running in one process. + +#### Pros +  * No communication overhead between subsystems, therefore slightly faster +  * Simpler deployment +  * Smaller memory footprint. Since we run all in one process, we don't have the overhead of multiple processes, runtimes and can share data. +  * Easier to observe and debug, no additional tools required +  +#### Cons +  * Harder to scale - only by scaling up your single machine +  * Lower resiliency. If one subsystem crashes the process, the whole thing goes down +  * It's a more or less self-contained system which is harder to extend + +## Distributed + +It's also possible to host OpenMU in a [distributed](/distributed/) way. However, this introduces a lot more complexity. +The communication between the subsystems is handled with Dapr. + +#### Pros +  * Easier to scale. For example, if you need additional game servers you simply add more containers. +  * Higher resiliency. If one subsystem crashes, the others are not affected. +  * It's easier to add more subsystems, even custom ones. +    For example, one could subscribe on already published events like guild messages or letters. + Such a subsystem could forward messages to other systems (E-Mail, Discord, etc.). + +#### Cons +  * Communication overhead between subsystems. +  * Higher memory footprint, since we run multiple docker containers +    (each with their own .net runtime) which can't share some data. +  * Harder to observe and debug. We added some stuff to compensate that (Loki, Grafana, Prometheus, Zipkin), but they require additional resources, too. + diff --git a/deploy/all-in-one/README.md b/deploy/all-in-one/README.md new file mode 100644 index 000000000..0c416d9cb --- /dev/null +++ b/deploy/all-in-one/README.md @@ -0,0 +1,62 @@ +# All-in-one deployment + +The all in one deployment is recommended, if you want to host on a small machine with a low amount of players. +In this case, all kinds of OpenMU subsystems (ConnectServer, GameServer, LoginServer, AdminPanel, ...) are running in one process. + +## Deployment with docker-compose + +### Install GIT + +See https://github.com/git-guides/install-git + +### Clone the repository + +> git clone https://github.com/MUnique/OpenMU.git + +### Navigate to the docker-compose files + +Navigate to the folder deploy/all-in-one + +### Option A - for local testing + +> docker-compose up -d + +And that's it ;-) + +However, if you want to make it available through the internet, you should choose Option B: + +### Option B - with HTTPS + +If you want to share your server with the world, it's recommended to set up HTTPS for nginx. +Otherwise, traffic from and to the admin panel is not encrypted. + +#### Adapt the config + +In the nginx.prod.conf, change "example.org" to your domain name. + +#### Run it + +> docker-compose up -f docker-compose.yml docker-compose.prod.yml -d + +#### Run certbot explicitly + +Hint: replace "example.org" with your domain. + +> docker compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org + +#### Set up certificate renewal +Because your certificates expire after 3 months, it's recommended to renew them regularly. +To renew it, run this command: + +> docker compose run --rm certbot renew + +Of course, it would make sense to add a cron job (e.g. once a week) on your host machine for that. + +## What's next + +Now, when you have deployed OpenMU, it's time to discover the AdminPanel. +If your containers run on docker at your local machine, you can simply go to http://localhost/ + +There you'll find a setup in the navigation menu, where you can select your desired game version, number of game servers (just the data of it), and if test accounts should be created. + +Click on 'Install', wait a bit until the database is set up and filled with the data and voila, OpenMU is ready to use. diff --git a/deploy/all-in-one/docker-compose-all-in-one.dcproj b/deploy/all-in-one/docker-compose-all-in-one.dcproj index 6ef70e6b7..0f054fed2 100644 --- a/deploy/all-in-one/docker-compose-all-in-one.dcproj +++ b/deploy/all-in-one/docker-compose-all-in-one.dcproj @@ -14,9 +14,14 @@ docker-compose.yml + + docker-compose.yml + - + + + \ No newline at end of file diff --git a/deploy/all-in-one/docker-compose.prod.yml b/deploy/all-in-one/docker-compose.prod.yml new file mode 100644 index 000000000..825e2c4c7 --- /dev/null +++ b/deploy/all-in-one/docker-compose.prod.yml @@ -0,0 +1,26 @@ +version: '3.4' + +services: + openmu-startup: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + database: + restart: "unless-stopped" + + nginx: + restart: "unless-stopped" + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.prod.conf:/etc/nginx/nginx.conf:ro + - ./.htpasswd:/etc/nginx/.htpasswd + - ./certbot/www:/var/www/certbot/:ro + - ./certbot/conf/:/etc/nginx/ssl/:ro + certbot: + image: certbot/certbot:latest + volumes: + - ./certbot/www/:/var/www/certbot/:rw + - ./certbot/conf/:/etc/letsencrypt/:rw \ No newline at end of file diff --git a/deploy/all-in-one/docker-compose.yml b/deploy/all-in-one/docker-compose.yml index f3ca80375..cbcbd3879 100644 --- a/deploy/all-in-one/docker-compose.yml +++ b/deploy/all-in-one/docker-compose.yml @@ -4,7 +4,6 @@ services: nginx: image: nginx:alpine container_name: nginx - restart: always ports: - "80:80" volumes: @@ -14,10 +13,8 @@ services: - openmu-startup openmu-startup: - image: ${DOCKER_REGISTRY-}openmu + image: munique/openmu container_name: openmu-startup - restart: unless-stopped - tty: true ports: - "80" - "55901:55901" @@ -27,7 +24,6 @@ services: - "55980:55980" environment: DB_HOST: database - # ASPNETCORE_URLS: http://+:1234 working_dir: /app/ volumes: - ./.htpasswd:/etc/nginx/.htpasswd @@ -36,7 +32,6 @@ services: database: image: postgres - restart: always container_name: database environment: POSTGRES_PASSWORD: admin diff --git a/deploy/all-in-one/nginx.conf b/deploy/all-in-one/nginx.dev.conf similarity index 100% rename from deploy/all-in-one/nginx.conf rename to deploy/all-in-one/nginx.dev.conf diff --git a/deploy/all-in-one/nginx.prod.conf b/deploy/all-in-one/nginx.prod.conf new file mode 100644 index 000000000..e6f45b6c2 --- /dev/null +++ b/deploy/all-in-one/nginx.prod.conf @@ -0,0 +1,50 @@ +events { +} + +http { + # this is required to proxy Grafana Live WebSocket connections. + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 80; + listen [::]:80; + + server_name example.org www.example.org; + server_tokens off; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://example.org$request_uri; + } + } + + server { + listen 443 default_server ssl http2; + listen [::]:443 ssl http2; + + server_name example.org; + + ssl_certificate /etc/nginx/ssl/live/example.org/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/live/example.org/privkey.pem; + + auth_basic "Protected Site"; + auth_basic_user_file /etc/nginx/.htpasswd; + + listen 80; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + resolver 127.0.0.11 ipv6=off; + + location / { + proxy_pass http://openmu-startup; + } + } +} \ No newline at end of file diff --git a/deploy/distributed/README.md b/deploy/distributed/README.md new file mode 100644 index 000000000..497adb582 --- /dev/null +++ b/deploy/distributed/README.md @@ -0,0 +1,69 @@ +# Distributed + +## Deployment with docker-compose + +Currently, we just have a docker-compose file for the deployment. +docker-compose has the limitation, that all runs on the same physical machine. + +For an even more distributed environment, with more machines, kubernetes can be used. +However, we don't have a finished configuration for kubernetes, yet. If you are familiar with kubernetes, +all contributions are welcome for kubernetes configuration files. + +So, these are the steps, if you want to deploy it with docker-compose: + +### Install GIT + +See https://github.com/git-guides/install-git + +### Clone the repository + +> git clone https://github.com/MUnique/OpenMU.git + +### Navigate to the docker-compose files + +Navigate to the folder deploy/distributed + +### Option A - for local testing + +> docker-compose up -d + +And that's it ;-) + +However, if you want to make it available through the internet, you should choose Option B: + +### Option B - with HTTPS + +If you want to share your server with the world, it's recommended to set up HTTPS for nginx. +Otherwise, traffic from and to the admin panel is not encrypted. + +#### Adapt the config + +In the nginx.prod.conf, change "example.org" to your domain name. + +#### Run it + +> docker-compose up -f docker-compose.yml docker-compose.prod.yml -d + +#### Run certbot explicitly + +Hint: replace "example.org" with your domain. + +> docker compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org + +#### Set up certificate renewal +Because your certificates expire after 3 months, it's recommended to renew them regularly. +To renew it, run this command: + +> docker compose run --rm certbot renew + +Of course, it would make sense to add a cron job (e.g. once a week) on your host machine for that. + +## What's next + +Now, when you have deployed OpenMU, it's time to discover the AdminPanel. + +If your containers run on docker at your local machine, you can simply go to http://localhost/admin + +There you'll find a setup in the navigation menu, where you can select your desired game version, number of game servers (just the data of it), and if test accounts should be created. + +Click on 'Install', wait a bit until the database is set up and filled with the data and voila, OpenMU is ready to use. diff --git a/deploy/distributed/docker-compose.dcproj b/deploy/distributed/docker-compose.dcproj index 0535a95ea..234340ab4 100644 --- a/deploy/distributed/docker-compose.dcproj +++ b/deploy/distributed/docker-compose.dcproj @@ -17,13 +17,18 @@ docker-compose.yml + + docker-compose.yml + - + + + \ No newline at end of file diff --git a/deploy/distributed/docker-compose.override.yml b/deploy/distributed/docker-compose.override.yml index 41de1fdac..8785ebee2 100644 --- a/deploy/distributed/docker-compose.override.yml +++ b/deploy/distributed/docker-compose.override.yml @@ -8,37 +8,57 @@ services: redis-state: ports: - "6379:6379" + + gameServer0: + environment: + ASPNETCORE_ENVIRONMENT: Development + ports: + - "81:80" gameServer1: environment: ASPNETCORE_ENVIRONMENT: Development ports: - - "81:80" + - "82:80" connectServer: + build: + context: ../../src + dockerfile: Dapr/ConnectServer.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development loginServer: + build: + context: ../../src + dockerfile: Dapr/LoginServer.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development friendServer: + build: + context: ../../src + dockerfile: Dapr/FriendServer.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development guildServer: + build: + context: ../../src + dockerfile: Dapr/GuildServer.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development chatServer: + build: + context: ../../src + dockerfile: Dapr/ChatServer.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development adminPanel: + build: + context: ../../src + dockerfile: Dapr/AdminPanel.Host/Dockerfile environment: ASPNETCORE_ENVIRONMENT: Development - # ASPNETCORE_Kestrel__Certificates__Default__Password: foobar - # ASPNETCORE_Kestrel__Certificates__Default__Path: /https/aspnetapp.pfx - # volumes: - # - ~/.aspnet/https:/https:ro diff --git a/deploy/distributed/docker-compose.prod.yml b/deploy/distributed/docker-compose.prod.yml new file mode 100644 index 000000000..c4b00af59 --- /dev/null +++ b/deploy/distributed/docker-compose.prod.yml @@ -0,0 +1,77 @@ +version: '3.4' + +services: + nginx: + restart: "unless-stopped" + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.prod.conf:/etc/nginx/nginx.conf:ro + - ./.htpasswd:/etc/nginx/.htpasswd + - ./certbot/www:/var/www/certbot/:ro + - ./certbot/conf/:/etc/nginx/ssl/:ro + certbot: + image: certbot/certbot:latest + volumes: + - ./certbot/www/:/var/www/certbot/:rw + - ./certbot/conf/:/etc/letsencrypt/:rw + + grafana: + restart: "unless-stopped" + prometheus: + restart: "unless-stopped" + loki: + restart: "unless-stopped" + minio: + restart: "unless-stopped" + redis-state: + restart: "unless-stopped" + dapr-placement: + restart: "unless-stopped" + pubsub: + restart: "unless-stopped" + database: + restart: "unless-stopped" + zipkin: + restart: "unless-stopped" + + connectServer: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + loginServer: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + friendServer: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + guildServer: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + chatServer: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + adminPanel: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + gameServer0: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production + + gameServer1: + restart: "unless-stopped" + environment: + ASPNETCORE_ENVIRONMENT: Production diff --git a/deploy/distributed/docker-compose.yml b/deploy/distributed/docker-compose.yml index 88dca847b..6998efada 100644 --- a/deploy/distributed/docker-compose.yml +++ b/deploy/distributed/docker-compose.yml @@ -13,12 +13,8 @@ services: ports: - "80:80" volumes: - - ./nginx.conf:/etc/nginx/nginx.conf + - ./nginx.dev.conf:/etc/nginx/nginx.conf - ./.htpasswd:/etc/nginx/.htpasswd - depends_on: - - adminPanel - - gameServer1 - - zipkin grafana: image: grafana/grafana:latest @@ -105,7 +101,7 @@ services: ports: - "5432" volumes: - - dbdata:/var/lib/postgresql/data #store data on volume + - dbdata:/var/lib/postgresql/data zipkin: image: openzipkin/zipkin @@ -115,11 +111,8 @@ services: - "9411:9411" connectServer: - image: ${DOCKER_REGISTRY-}openmu-cs + image: munique/openmu-connect container_name: connectServer - build: - context: ../../src - dockerfile: Dapr/ConnectServer.Host/Dockerfile ports: - "50010:50001" - "44405:44405" @@ -145,11 +138,8 @@ services: - "./dapr-components/:/components" loginServer: - image: ${DOCKER_REGISTRY-}openmu-login + image: munique/openmu-login container_name: loginServer - build: - context: ../../src - dockerfile: Dapr/LoginServer.Host/Dockerfile ports: - "50011:50001" - "9464" # Prometheus @@ -171,11 +161,8 @@ services: - "./dapr-components/:/components" friendServer: - image: ${DOCKER_REGISTRY-}openmu-friends + image: munique/openmu-friend container_name: friendServer - build: - context: ../../src - dockerfile: Dapr/FriendServer.Host/Dockerfile ports: - "50012:50001" - "9464" # Prometheus @@ -198,11 +185,8 @@ services: - "./dapr-components/:/components" guildServer: - image: ${DOCKER_REGISTRY-}openmu-guilds + image: munique/openmu-guild container_name: guildServer - build: - context: ../../src - dockerfile: Dapr/GuildServer.Host/Dockerfile ports: - "50013:50001" - "9464" # Prometheus @@ -224,11 +208,8 @@ services: - "./dapr-components/:/components" chatServer: - image: ${DOCKER_REGISTRY-}openmu-chat + image: munique/openmu-chat container_name: chatServer - build: - context: ../../src - dockerfile: Dapr/ChatServer.Host/Dockerfile environment: APPID: chatServer ports: @@ -254,11 +235,8 @@ services: adminPanel: - image: ${DOCKER_REGISTRY-}openmu-admin + image: munique/openmu-admin container_name: adminPanel - build: - context: ../../src - dockerfile: Dapr/AdminPanel.Host/Dockerfile depends_on: - database ports: @@ -284,9 +262,9 @@ services: volumes: - "./dapr-components/:/components" - gameServer1: - image: ${DOCKER_REGISTRY-}openmu-gs - container_name: gameServer1 + gameServer0: + image: munique/openmu-game + container_name: gameServer0 build: context: ../../src dockerfile: Dapr/GameServer.Host/Dockerfile @@ -297,6 +275,43 @@ services: - "9464" # Prometheus environment: GS_ID: 0 + APPID: gameServer0 + PATH_BASE: /gameServer/0/ + depends_on: + - connectServer-dapr + - loginServer-dapr + - friendServer-dapr + - pubsub + - zipkin + - database + - loki + + gameServer0-dapr: + image: "daprio/daprd:latest" + container_name: gameserver0_dapr + command: [ "./daprd", "-app-id", "gameServer0", "-app-port", "80", + "-components-path", "/components", + "-config", "/components/config.yaml", + "-placement-host-address", "dapr-placement:50006" ] + depends_on: + - gameServer0 + network_mode: "service:gameServer0" + volumes: + - "./dapr-components/:/components" + + gameServer1: + image: munique/openmu-game + container_name: gameServer1 + build: + context: ../../src + dockerfile: Dapr/GameServer.Host/Dockerfile + ports: + - "80" + - "50001:50001" + - "55902:55902" + - "9464" # Prometheus + environment: + GS_ID: 1 APPID: gameServer1 PATH_BASE: /gameServer/1/ depends_on: @@ -319,5 +334,4 @@ services: - gameServer1 network_mode: "service:gameServer1" volumes: - - "./dapr-components/:/components" - + - "./dapr-components/:/components" \ No newline at end of file diff --git a/deploy/distributed/nginx.conf b/deploy/distributed/nginx.dev.conf similarity index 100% rename from deploy/distributed/nginx.conf rename to deploy/distributed/nginx.dev.conf diff --git a/deploy/distributed/nginx.prod.conf b/deploy/distributed/nginx.prod.conf new file mode 100644 index 000000000..080835b15 --- /dev/null +++ b/deploy/distributed/nginx.prod.conf @@ -0,0 +1,88 @@ +events { +} + +http { + # this is required to proxy Grafana Live WebSocket connections. + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 80; + listen [::]:80; + + server_name example.org www.example.org; + server_tokens off; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://example.org$request_uri; + } + } + + server { + listen 443 default_server ssl http2; + listen [::]:443 ssl http2; + + server_name example.org; + + ssl_certificate /etc/nginx/ssl/live/example.org/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/live/example.org/privkey.pem; + + auth_basic "Protected Site"; + auth_basic_user_file /etc/nginx/.htpasswd; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + resolver 127.0.0.11 ipv6=off; + + location /zipkin { + proxy_pass http://zipkin:9411/zipkin/; + } + + location /grafana/ { + proxy_set_header Host $http_host; + proxy_pass http://grafana:3000/; + + # Auth by nginx + proxy_set_header X-WEBAUTH-USER $remote_user; + proxy_set_header Authorization ""; + } + + # Proxy Grafana Live WebSocket connections. + location /grafana/api/live { + rewrite ^/grafana/(.*) /$1 break; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $http_host; + + proxy_pass http://grafana:3000/; + + # Auth by nginx + proxy_set_header X-WEBAUTH-USER $remote_user; + proxy_set_header Authorization ""; + } + + location ~ (/admin)(.*) { + proxy_pass http://adminPanel/admin$2; + } + + # Public API + location ~ (/serverInfo)(.*) { + proxy_pass http://connectServer/serverInfo$2; + auth_basic off; + } + + # Game Servers: + location ~ (/gameServer/(\d+)(.*)) { + proxy_pass http://gameServer$2$1; + } + } +} \ No newline at end of file diff --git a/src/Dapr/AdminPanel.Host/Dockerfile b/src/Dapr/AdminPanel.Host/Dockerfile index 2ae57f6b5..b9b51e84a 100644 --- a/src/Dapr/AdminPanel.Host/Dockerfile +++ b/src/Dapr/AdminPanel.Host/Dockerfile @@ -1,9 +1,8 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base WORKDIR /app EXPOSE 80 -EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src RUN dotnet restore "Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj" diff --git a/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj b/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj index 3654bbdad..f6d4427f9 100644 --- a/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj +++ b/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Dapr/AdminPanel.Host/Properties/AssemblyInfo.cs b/src/Dapr/AdminPanel.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..be3d110df --- /dev/null +++ b/src/Dapr/AdminPanel.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.AdminPanel.Host")] \ No newline at end of file diff --git a/src/Dapr/ChatServer.Host/Dockerfile b/src/Dapr/ChatServer.Host/Dockerfile index 300366cba..d284ae6b9 100644 --- a/src/Dapr/ChatServer.Host/Dockerfile +++ b/src/Dapr/ChatServer.Host/Dockerfile @@ -1,13 +1,10 @@ FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base WORKDIR /app EXPOSE 80 - -RUN addgroup -S dotnet && adduser -S dotnet -G dotnet \ - && apk add --no-cache dumb-init +EXPOSE 55980 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj", "Dapr/ChatServer.Host/"] RUN dotnet restore "Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/ChatServer.Host" @@ -18,8 +15,5 @@ RUN dotnet publish "MUnique.OpenMU.ChatServer.Host.csproj" -c Release -o /app/pu FROM base AS final WORKDIR /app -RUN chown dotnet /app -COPY --chown=dotnet:dotnet-group --from=publish /app/publish . - -USER dotnet -CMD ["dumb-init", "dotnet", "MUnique.OpenMU.ChatServer.Host.dll"] +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "MUnique.OpenMU.ChatServer.Host.dll"] diff --git a/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj b/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj index d9c304513..08011c6c6 100644 --- a/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj +++ b/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Dapr/ChatServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/ChatServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..bad980ab5 --- /dev/null +++ b/src/Dapr/ChatServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.ChatServer.Host")] \ No newline at end of file diff --git a/src/Dapr/Common/AssemblyInfo.cs b/src/Dapr/Common/AssemblyInfo.cs new file mode 100644 index 000000000..dab436691 --- /dev/null +++ b/src/Dapr/Common/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.Dapr.Common")] \ No newline at end of file diff --git a/src/Dapr/ConnectServer.Host/Dockerfile b/src/Dapr/ConnectServer.Host/Dockerfile index 005be64c1..6be0b0664 100644 --- a/src/Dapr/ConnectServer.Host/Dockerfile +++ b/src/Dapr/ConnectServer.Host/Dockerfile @@ -1,10 +1,10 @@ FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base WORKDIR /app EXPOSE 80 +EXPOSE 44405 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj", "Dapr/ConnectServer.Host/"] RUN dotnet restore "Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/ConnectServer.Host" diff --git a/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj b/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj index 7c4e1ff83..f7678c458 100644 --- a/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj +++ b/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Dapr/ConnectServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/ConnectServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8a2295bfa --- /dev/null +++ b/src/Dapr/ConnectServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.ConnectServer.Host")] \ No newline at end of file diff --git a/src/Dapr/FriendServer.Host/Dockerfile b/src/Dapr/FriendServer.Host/Dockerfile index b2fdeae0d..85944286d 100644 --- a/src/Dapr/FriendServer.Host/Dockerfile +++ b/src/Dapr/FriendServer.Host/Dockerfile @@ -4,7 +4,6 @@ EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj", "Dapr/FriendServer.Host/"] RUN dotnet restore "Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/FriendServer.Host" diff --git a/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj b/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj index 938b9d3b5..e096b89df 100644 --- a/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj +++ b/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Dapr/FriendServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/FriendServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2c911fd5d --- /dev/null +++ b/src/Dapr/FriendServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.FriendServer.Host")] \ No newline at end of file diff --git a/src/Dapr/GameServer.Host/Dockerfile b/src/Dapr/GameServer.Host/Dockerfile index 4367329d9..04dbfbe7f 100644 --- a/src/Dapr/GameServer.Host/Dockerfile +++ b/src/Dapr/GameServer.Host/Dockerfile @@ -4,7 +4,6 @@ EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj", "Dapr/GameServer.Host/"] RUN dotnet restore "Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/GameServer.Host" diff --git a/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj b/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj index df5ca717e..213dd49b1 100644 --- a/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj +++ b/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj @@ -29,7 +29,7 @@ - + diff --git a/src/Dapr/GameServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/GameServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ca24b09a9 --- /dev/null +++ b/src/Dapr/GameServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.GameServer.Host")] \ No newline at end of file diff --git a/src/Dapr/GuildServer.Host/Dockerfile b/src/Dapr/GuildServer.Host/Dockerfile index 850a4042c..1b977893d 100644 --- a/src/Dapr/GuildServer.Host/Dockerfile +++ b/src/Dapr/GuildServer.Host/Dockerfile @@ -4,7 +4,6 @@ EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj", "Dapr/GuildServer.Host/"] RUN dotnet restore "Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/GuildServer.Host" diff --git a/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj b/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj index 1201ab5e3..03067347d 100644 --- a/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj +++ b/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Dapr/GuildServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/GuildServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..3d520084a --- /dev/null +++ b/src/Dapr/GuildServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.GuildServer.Host")] \ No newline at end of file diff --git a/src/Dapr/LoginServer.Host/Dockerfile b/src/Dapr/LoginServer.Host/Dockerfile index 9e870e397..9f1d70822 100644 --- a/src/Dapr/LoginServer.Host/Dockerfile +++ b/src/Dapr/LoginServer.Host/Dockerfile @@ -4,7 +4,6 @@ EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src -COPY ["Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj", "Dapr/LoginServer.Host/"] RUN dotnet restore "Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj" COPY . . WORKDIR "/src/Dapr/LoginServer.Host" diff --git a/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj b/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj index 8cfdb7920..45910ceb8 100644 --- a/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj +++ b/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/Dapr/LoginServer.Host/Properties/AssemblyInfo.cs b/src/Dapr/LoginServer.Host/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d91a4453a --- /dev/null +++ b/src/Dapr/LoginServer.Host/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.LoginServer.Host")] \ No newline at end of file diff --git a/src/Dapr/ServerClients/AssemblyInfo.cs b/src/Dapr/ServerClients/AssemblyInfo.cs new file mode 100644 index 000000000..1b92f5b7f --- /dev/null +++ b/src/Dapr/ServerClients/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MUnique.OpenMU.ServerClients")] \ No newline at end of file diff --git a/src/Dapr/ServerClients/FriendServer.cs b/src/Dapr/ServerClients/FriendServer.cs index 02d42834c..b26123e1c 100644 --- a/src/Dapr/ServerClients/FriendServer.cs +++ b/src/Dapr/ServerClients/FriendServer.cs @@ -5,6 +5,7 @@ namespace MUnique.OpenMU.ServerClients; using Microsoft.Extensions.Logging; +using Nito.AsyncEx.Synchronous; using Dapr.Client; using MUnique.OpenMU.Interfaces; @@ -34,7 +35,7 @@ public void ForwardLetter(LetterHeader letter) { try { - this._daprClient.PublishEventAsync("pubsub", nameof(IGameServer.LetterReceived), letter); + this._daprClient.PublishEventAsync("pubsub", nameof(IGameServer.LetterReceived), letter).WaitAndUnwrapException(); } catch (Exception ex) { @@ -47,7 +48,7 @@ public void FriendResponse(string characterName, string friendName, bool accepte { try { - this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.FriendResponse), new FriendResponseArguments(characterName, friendName, accepted)); + this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.FriendResponse), new FriendResponseArguments(characterName, friendName, accepted)).WaitAndUnwrapException(); } catch (Exception ex) { @@ -72,7 +73,7 @@ public void SetPlayerVisibilityState(byte serverId, Guid characterId, string cha { try { - this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.SetPlayerVisibilityState), new PlayerFriendOnlineStateArguments(characterId, characterName, serverId, isVisible)); + this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.SetPlayerVisibilityState), new PlayerFriendOnlineStateArguments(characterId, characterName, serverId, isVisible)).WaitAndUnwrapException(); } catch (Exception ex) { @@ -85,7 +86,7 @@ public bool FriendRequest(string playerName, string friendName) { try { - return this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.FriendRequest), new RequestArguments(playerName, friendName)).Result; + return this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.FriendRequest), new RequestArguments(playerName, friendName)).WaitAndUnwrapException(); } catch (Exception ex) { @@ -99,7 +100,7 @@ public void DeleteFriend(string name, string friendName) { try { - this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.DeleteFriend), new RequestArguments(name, friendName)); + this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.DeleteFriend), new RequestArguments(name, friendName)).WaitAndUnwrapException(); } catch (Exception ex) { @@ -112,7 +113,7 @@ public void CreateChatRoom(string playerName, string friendName) { try { - this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.CreateChatRoom), new RequestArguments(playerName, friendName)); + this._daprClient.InvokeMethodAsync(this._targetAppId, nameof(this.CreateChatRoom), new RequestArguments(playerName, friendName)).WaitAndUnwrapException(); } catch (Exception ex) { diff --git a/src/Persistence/EntityFramework/EntityFrameworkContextBase.cs b/src/Persistence/EntityFramework/EntityFrameworkContextBase.cs index f644692c6..db0e6761f 100644 --- a/src/Persistence/EntityFramework/EntityFrameworkContextBase.cs +++ b/src/Persistence/EntityFramework/EntityFrameworkContextBase.cs @@ -2,14 +2,13 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. // -using MUnique.OpenMU.Interfaces; - namespace MUnique.OpenMU.Persistence.EntityFramework; using System.Collections; using System.Reflection; using Microsoft.EntityFrameworkCore; using MUnique.OpenMU.DataModel.Composition; +using MUnique.OpenMU.Interfaces; /// /// Abstract base class for an which uses an . diff --git a/src/Startup/Dockerfile b/src/Startup/Dockerfile index 5ef423b5a..fe56a45e8 100644 --- a/src/Startup/Dockerfile +++ b/src/Startup/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base WORKDIR /app EXPOSE 80 EXPOSE 55901 @@ -7,7 +7,7 @@ EXPOSE 55903 EXPOSE 44405 EXPOSE 55980 -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src RUN dotnet restore "Startup/MUnique.OpenMU.Startup.csproj" diff --git a/src/Web/AdminPanel/Components/Install.razor b/src/Web/AdminPanel/Components/Install.razor index abe4fdc7f..852c4b2af 100644 --- a/src/Web/AdminPanel/Components/Install.razor +++ b/src/Web/AdminPanel/Components/Install.razor @@ -11,10 +11,22 @@ else if (this.IsInstalling) else if (this.IsInstalled) {

Finished! Have fun :)

-

Please restart the admin panel / server.

+ if (!AdminPanelEnvironment.IsHostingEmbedded) + { +

Please restart the connect and game server containers.

+ } + + } else { + if (this.CurrentConnections > 0) + { + + } +

Select the game version

@@ -46,7 +58,14 @@ else

- + @if (this.CurrentConnections == 0) + { + + } + else + { + + }

} diff --git a/src/Web/AdminPanel/Components/Install.razor.cs b/src/Web/AdminPanel/Components/Install.razor.cs index ae1f20931..dc5c57fdc 100644 --- a/src/Web/AdminPanel/Components/Install.razor.cs +++ b/src/Web/AdminPanel/Components/Install.razor.cs @@ -5,13 +5,14 @@ namespace MUnique.OpenMU.Web.AdminPanel.Components; using Microsoft.AspNetCore.Components; +using MUnique.OpenMU.Interfaces; using MUnique.OpenMU.Persistence.Initialization; using MUnique.OpenMU.Web.AdminPanel.Services; /// /// The component which allows to initialize the database. /// -public partial class Install +public sealed partial class Install { /// /// Gets or sets the selected version. @@ -38,6 +39,8 @@ public partial class Install /// public bool IsInstalled { get; private set; } + private int CurrentConnections => this.ServerProvider.Servers.Where(s => s.ServerState != ServerState.Timeout).Sum(s => s.CurrentConnections); + /// /// Gets or sets the installation finished callback. /// @@ -50,6 +53,12 @@ public partial class Install [Inject] public SetupService SetupService { get; set; } = null!; + /// + /// Gets or sets the server provider. + /// + [Inject] + public IServerProvider ServerProvider { get; set; } = null!; + /// protected override void OnParametersSet() { @@ -78,7 +87,6 @@ private async Task StartInstallation() { this.IsInstalled = true; this.IsInstalling = false; - await this.InstallationFinished.InvokeAsync(); } } diff --git a/src/Web/AdminPanel/Pages/GameServer.razor b/src/Web/AdminPanel/Pages/GameServer.razor index ed93ad69c..0aba921f2 100644 --- a/src/Web/AdminPanel/Pages/GameServer.razor +++ b/src/Web/AdminPanel/Pages/GameServer.razor @@ -1,4 +1,4 @@ -@page "/gameServer/{gameServerNumber:int}/" +@page "/gameServer/{gameServerId:int}/" @using MUnique.OpenMU.Web.Map.Components @using MUnique.OpenMU.Web.Map @@ -25,17 +25,20 @@ [Inject] public IList Servers { get; set; } = null!; + /// + /// Gets or sets the 0-based game server id/index. + /// [Parameter] - public int GameServerNumber { get; set; } + public int GameServerId { get; set; } /// protected override Task OnInitializedAsync() { - var gameServer = this.Servers.OfType().First(gs => gs.Id == this.GameServerNumber - 1); + var gameServer = this.Servers.OfType().First(gs => gs.Id == this.GameServerId); var context = (gameServer as IGameServerContextProvider)?.Context ?? throw new InvalidOperationException("This map page just works in a All-In-One deployment."); this._gameServer = new ObservableGameServerAdapter(context); - this._liveMapRoute = $"gameServer/{this.GameServerNumber}/map/"; + this._liveMapRoute = $"gameServer/{this.GameServerId}/map/"; return base.OnInitializedAsync(); } } diff --git a/src/Web/AdminPanel/Pages/MapPage.razor b/src/Web/AdminPanel/Pages/MapPage.razor index fb414cc4b..2191ae5b6 100644 --- a/src/Web/AdminPanel/Pages/MapPage.razor +++ b/src/Web/AdminPanel/Pages/MapPage.razor @@ -1,4 +1,4 @@ -@page "/gameServer/{gameServerNumber:int}/map/{mapId:guid}" +@page "/gameServer/{gameServerId:int}/map/{mapId:guid}" @using MUnique.OpenMU.Web.Map.Components @using MUnique.OpenMU.Web.Map @@ -39,19 +39,16 @@ public Guid MapId { get; set; } /// - /// Gets or sets the game server number. + /// Gets or sets the game server id/index. /// - /// - /// It's 1 higher than the id. - /// [Parameter] - public int GameServerNumber { get; set; } + public int GameServerId { get; set; } /// protected override Task OnInitializedAsync() { - var gameServer = this.Servers.OfType().First(gs => gs.Id == this.GameServerNumber - 1); + var gameServer = this.Servers.OfType().First(gs => gs.Id == this.GameServerId); var context = (gameServer as IGameServerContextProvider)?.Context ?? throw new InvalidOperationException("This map page just works in a All-In-One deployment."); this._gameServer = new ObservableGameServerAdapter(context);