diff --git a/Dockerfile b/Dockerfile
index c76c08c..c1cf12a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,7 +23,7 @@ EXPOSE 8000
# up the FastAPI workers.
# NOTE: If you run this Dockerfile via "docker compose up", CMD will be overridden
# by docker-compose.yaml
-CMD ["gunicorn", "app.main:sio_app", \
+CMD ["gunicorn", "app.main:main_app", \
"--bind", "0.0.0.0:8000", \
"--access-logfile", "-", \
"--workers", "1", \
diff --git a/app/config.py b/app/config.py
index 5b36fed..37b5984 100644
--- a/app/config.py
+++ b/app/config.py
@@ -14,6 +14,7 @@ class Settings(BaseSettings):
enable_examples: bool = True
enable_excel_online: bool = True
enable_htmx: bool = True
+ enable_socketio: bool = True
entraid_client_id: Optional[str] = None
entraid_tenant_id: Optional[str] = None
# Set to False if you have users from external organizations
diff --git a/app/main.py b/app/main.py
index d6c7a9e..1b26524 100644
--- a/app/main.py
+++ b/app/main.py
@@ -21,11 +21,6 @@
# App
app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
-# Routers
-app.include_router(xlwings_router)
-app.include_router(macros_router)
-app.include_router(taskpane_router)
-
# CORS: Office Scripts and custom functions in Excel on the web require CORS
# Using app.add_middleware won't add the CORS headers if you handle the root "Exception"
# in an exception handler (it would require a specific exception type).
@@ -36,7 +31,17 @@
)
# Socket.io
-sio_app = socketio.ASGIApp(socketio_router.sio, cors_app)
+if settings.enable_socketio:
+ sio_app = socketio.ASGIApp(socketio_router.sio, cors_app)
+ main_app = sio_app
+else:
+ main_app = cors_app
+
+
+# Routers
+app.include_router(xlwings_router)
+app.include_router(macros_router)
+app.include_router(taskpane_router)
# Security headers
diff --git a/app/static/js/socketio-handlers.js b/app/static/js/socketio-handlers.js
index 9833242..33353b4 100644
--- a/app/static/js/socketio-handlers.js
+++ b/app/static/js/socketio-handlers.js
@@ -9,6 +9,6 @@ try {
},
});
} catch (error) {
- console.error(error);
+ console.log("Didn't load socket.io: ", error);
globalThis.socket = null;
}
diff --git a/app/templates/base.html b/app/templates/base.html
index 4895a25..152edf0 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -22,7 +22,9 @@
{% endif %}
{# Socket.io (must come before xlwings.js) #}
-
+ {% if settings.enable_socketio %}
+
+ {% endif %}
{# xlwings.js (must come before custom-function-code) #}
{# Examples #}
diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml
index c5ad2b3..0d865fd 100644
--- a/docker-compose.prod.yaml
+++ b/docker-compose.prod.yaml
@@ -3,7 +3,7 @@ services:
app:
build: .
command: >
- gunicorn app.main:sio_app
+ gunicorn app.main:main_app
--bind 0.0.0.0:8000
--access-logfile -
--workers 1
diff --git a/docker-compose.yaml b/docker-compose.yaml
index c22c066..0f38bec 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -3,7 +3,7 @@ services:
app:
build: .
command: >
- uvicorn app.main:sio_app
+ uvicorn app.main:main_app
--host 0.0.0.0 --port 8000
--ssl-keyfile /project/certs/localhost+2-key.pem --ssl-certfile /project/certs/localhost+2.pem
--reload
diff --git a/function_app.py b/function_app.py
new file mode 100644
index 0000000..864fe48
--- /dev/null
+++ b/function_app.py
@@ -0,0 +1,21 @@
+"""
+Azure Functions
+
+Note: Azure Functions don't support streaming functions/socket.io.
+
+The other files required for Azure Functions are:
+- host.json
+- local.settings.json
+
+The function is always called http_app_func, see:
+https://github.com/Azure-Samples/fastapi-on-azure-functions/issues/31
+
+For app logs, in Azure portal go to:
+Function App > My Function App. Than, under `http_app_func`, click on `Invocations and more`.
+"""
+
+import azure.functions as func
+
+from app.main import main_app
+
+app = func.AsgiFunctionApp(app=main_app, http_auth_level=func.AuthLevel.ANONYMOUS)
diff --git a/host.json b/host.json
new file mode 100644
index 0000000..a3a3a7e
--- /dev/null
+++ b/host.json
@@ -0,0 +1,22 @@
+{
+ "version": "2.0",
+ "logging": {
+ "applicationInsights": {
+ "samplingSettings": {
+ "isEnabled": true,
+ "excludedTypes": "Request"
+ }
+ }
+ },
+ "extensionBundle": {
+ "id": "Microsoft.Azure.Functions.ExtensionBundle",
+ "version": "[2.*, 3.0.0)"
+ },
+ "extensions":
+ {
+ "http":
+ {
+ "routePrefix": ""
+ }
+ }
+}
diff --git a/local.settings.json b/local.settings.json
new file mode 100644
index 0000000..fb158d7
--- /dev/null
+++ b/local.settings.json
@@ -0,0 +1,8 @@
+{
+ "IsEncrypted": false,
+ "Values": {
+ "AzureWebJobsStorage": "",
+ "FUNCTIONS_WORKER_RUNTIME": "python",
+ "AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
+ }
+}
diff --git a/requirements.in b/requirements.in
index d00f903..a27b5c5 100644
--- a/requirements.in
+++ b/requirements.in
@@ -1,3 +1,4 @@
+azure-functions; sys_platform != 'win32'
cachetools
fastapi
gunicorn; sys_platform != 'win32'
diff --git a/requirements.txt b/requirements.txt
index 846ed3e..ec33ecb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,6 +7,7 @@ anyio==4.3.0
# httpx
# starlette
# watchfiles
+azure-functions==1.19.0
bidict==0.23.1
# via python-socketio
cachetools==5.3.3
diff --git a/run.py b/run.py
index 2fcb4d6..1654fe5 100644
--- a/run.py
+++ b/run.py
@@ -6,7 +6,7 @@
if __name__ == "__main__":
uvicorn.run(
- "app.main:sio_app",
+ "app.main:main_app",
host="127.0.0.1",
port=8000,
reload=True,