mirror of https://github.com/zulip/zulip.git
katex: Replace subprocess call with minimal external service.
Replace a separate call to subprocess, starting `node` from scratch, with an optional standalone node Express service which performs the rendering. In benchmarking, this reduces the overhead of a KaTeX call from 120ms to 2.8ms. This is notable because enough calls to KaTeX in a single message would previously time out the whole message rendering. The service is optional because he majority of deployments do not use enough LaTeX to merit the additional memory usage (60Mb). Fixes: #17425.
This commit is contained in:
parent
5fd38f15a6
commit
c13e3dee24
|
@ -277,6 +277,12 @@
|
||||||
],
|
],
|
||||||
"unicorn/prefer-string-replace-all": "off"
|
"unicorn/prefer-string-replace-all": "off"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["web/server/**"],
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,18 @@ more than 3.5GiB of RAM, 4 on hosts with less.
|
||||||
Number of days of access logs to keep, for both nginx and the application.
|
Number of days of access logs to keep, for both nginx and the application.
|
||||||
Defaults to 14 days.
|
Defaults to 14 days.
|
||||||
|
|
||||||
|
#### `katex_server`
|
||||||
|
|
||||||
|
Set to a true value to run a separate service for [rendering math with
|
||||||
|
LaTeX](https://zulip.com/help/latex). This is not necessary except on servers
|
||||||
|
with users who send several math blocks in a single message; it will address
|
||||||
|
issues with such messages occasionally failing to send, at cost of a small
|
||||||
|
amount of increased memory usage.
|
||||||
|
|
||||||
|
#### `katex_server_port`
|
||||||
|
|
||||||
|
Set to the port number for the KaTeX server, if enabled; defaults to port 9700.
|
||||||
|
|
||||||
### `[postfix]`
|
### `[postfix]`
|
||||||
|
|
||||||
#### `mailname`
|
#### `mailname`
|
||||||
|
|
|
@ -10,8 +10,12 @@
|
||||||
"@formatjs/intl": "^2.0.0",
|
"@formatjs/intl": "^2.0.0",
|
||||||
"@giphy/js-components": "^5.0.5",
|
"@giphy/js-components": "^5.0.5",
|
||||||
"@giphy/js-fetch-api": "^5.0.0",
|
"@giphy/js-fetch-api": "^5.0.0",
|
||||||
|
"@koa/bodyparser": "^5.0.0",
|
||||||
"@sentry/browser": "^7.51.2",
|
"@sentry/browser": "^7.51.2",
|
||||||
"@sentry/integrations": "^7.51.2",
|
"@sentry/integrations": "^7.51.2",
|
||||||
|
"@types/co-body": "^6.1.3",
|
||||||
|
"@types/koa": "^2.15.0",
|
||||||
|
"@types/koa-bodyparser": "^4.3.12",
|
||||||
"@uppy/core": "^3.0.2",
|
"@uppy/core": "^3.0.2",
|
||||||
"@uppy/progress-bar": "^3.0.1",
|
"@uppy/progress-bar": "^3.0.1",
|
||||||
"@uppy/xhr-upload": "^3.0.2",
|
"@uppy/xhr-upload": "^3.0.2",
|
||||||
|
@ -26,6 +30,7 @@
|
||||||
"clean-css": "^5.1.0",
|
"clean-css": "^5.1.0",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"colord": "^2.9.3",
|
"colord": "^2.9.3",
|
||||||
|
"config-ini-parser": "^1.6.1",
|
||||||
"core-js": "^3.36.0",
|
"core-js": "^3.36.0",
|
||||||
"css-loader": "^6.2.0",
|
"css-loader": "^6.2.0",
|
||||||
"css-minimizer-webpack-plugin": "^6.0.0",
|
"css-minimizer-webpack-plugin": "^6.0.0",
|
||||||
|
@ -50,6 +55,7 @@
|
||||||
"jquery-validation": "^1.19.0",
|
"jquery-validation": "^1.19.0",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"katex": "^0.16.2",
|
"katex": "^0.16.2",
|
||||||
|
"koa": "^2.15.0",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
"micromodal": "^0.4.6",
|
"micromodal": "^0.4.6",
|
||||||
"mini-css-extract-plugin": "^2.2.2",
|
"mini-css-extract-plugin": "^2.2.2",
|
||||||
|
|
220
pnpm-lock.yaml
220
pnpm-lock.yaml
|
@ -37,12 +37,24 @@ dependencies:
|
||||||
'@giphy/js-fetch-api':
|
'@giphy/js-fetch-api':
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.4.0
|
version: 5.4.0
|
||||||
|
'@koa/bodyparser':
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0
|
||||||
'@sentry/browser':
|
'@sentry/browser':
|
||||||
specifier: ^7.51.2
|
specifier: ^7.51.2
|
||||||
version: 7.106.1
|
version: 7.106.1
|
||||||
'@sentry/integrations':
|
'@sentry/integrations':
|
||||||
specifier: ^7.51.2
|
specifier: ^7.51.2
|
||||||
version: 7.106.1
|
version: 7.106.1
|
||||||
|
'@types/co-body':
|
||||||
|
specifier: ^6.1.3
|
||||||
|
version: 6.1.3
|
||||||
|
'@types/koa':
|
||||||
|
specifier: ^2.15.0
|
||||||
|
version: 2.15.0
|
||||||
|
'@types/koa-bodyparser':
|
||||||
|
specifier: ^4.3.12
|
||||||
|
version: 4.3.12
|
||||||
'@uppy/core':
|
'@uppy/core':
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.9.3
|
version: 3.9.3
|
||||||
|
@ -85,6 +97,9 @@ dependencies:
|
||||||
colord:
|
colord:
|
||||||
specifier: ^2.9.3
|
specifier: ^2.9.3
|
||||||
version: 2.9.3
|
version: 2.9.3
|
||||||
|
config-ini-parser:
|
||||||
|
specifier: ^1.6.1
|
||||||
|
version: 1.6.1
|
||||||
core-js:
|
core-js:
|
||||||
specifier: ^3.36.0
|
specifier: ^3.36.0
|
||||||
version: 3.36.0
|
version: 3.36.0
|
||||||
|
@ -157,6 +172,9 @@ dependencies:
|
||||||
katex:
|
katex:
|
||||||
specifier: ^0.16.2
|
specifier: ^0.16.2
|
||||||
version: 0.16.9
|
version: 0.16.9
|
||||||
|
koa:
|
||||||
|
specifier: ^2.15.0
|
||||||
|
version: 2.15.0
|
||||||
lodash:
|
lodash:
|
||||||
specifier: ^4.17.19
|
specifier: ^4.17.19
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
|
@ -2605,6 +2623,15 @@ packages:
|
||||||
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
|
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@koa/bodyparser@5.0.0:
|
||||||
|
resolution: {integrity: sha512-JEiZVe2e85qPOqA+Nw/SJC5fkFw3XSekh0RSoqz5F6lFYuhEspgqAb972rQRCJesv27QUsz96vU/Vb92wF1GUg==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
dependencies:
|
||||||
|
co-body: 6.1.0
|
||||||
|
lodash.merge: 4.6.2
|
||||||
|
type-is: 1.6.18
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@leichtgewicht/ip-codec@2.0.4:
|
/@leichtgewicht/ip-codec@2.0.4:
|
||||||
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
|
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
|
||||||
|
|
||||||
|
@ -2946,6 +2973,12 @@ packages:
|
||||||
'@turf/helpers': 6.5.0
|
'@turf/helpers': 6.5.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/accepts@1.3.7:
|
||||||
|
resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.11.27
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/autosize@4.0.3:
|
/@types/autosize@4.0.3:
|
||||||
resolution: {integrity: sha512-o0ZyU3ePp3+KRbhHsY4ogjc+ZQWgVN5h6j8BHW5RII4cFKi6PEKK9QPAcphJVkD0dGpyFnD3VRR0WMvHVjCv9w==}
|
resolution: {integrity: sha512-o0ZyU3ePp3+KRbhHsY4ogjc+ZQWgVN5h6j8BHW5RII4cFKi6PEKK9QPAcphJVkD0dGpyFnD3VRR0WMvHVjCv9w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -3007,6 +3040,13 @@ packages:
|
||||||
source-map: /source-map-js@1.0.1
|
source-map: /source-map-js@1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/co-body@6.1.3:
|
||||||
|
resolution: {integrity: sha512-UhuhrQ5hclX6UJctv5m4Rfp52AfG9o9+d9/HwjxhVB5NjXxr5t9oKgJxN8xRHgr35oo8meUEHUPFWiKg6y71aA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.11.27
|
||||||
|
'@types/qs': 6.9.12
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/connect-history-api-fallback@1.5.4:
|
/@types/connect-history-api-fallback@1.5.4:
|
||||||
resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==}
|
resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -3018,6 +3058,19 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.11.27
|
'@types/node': 20.11.27
|
||||||
|
|
||||||
|
/@types/content-disposition@0.5.8:
|
||||||
|
resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/cookies@0.9.0:
|
||||||
|
resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==}
|
||||||
|
dependencies:
|
||||||
|
'@types/connect': 3.4.38
|
||||||
|
'@types/express': 4.17.21
|
||||||
|
'@types/keygrip': 1.0.6
|
||||||
|
'@types/node': 20.11.27
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/eslint-scope@3.7.7:
|
/@types/eslint-scope@3.7.7:
|
||||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -3053,6 +3106,10 @@ packages:
|
||||||
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
|
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/http-assert@1.5.5:
|
||||||
|
resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/http-errors@2.0.4:
|
/@types/http-errors@2.0.4:
|
||||||
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||||
|
|
||||||
|
@ -3103,6 +3160,35 @@ packages:
|
||||||
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
|
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/keygrip@1.0.6:
|
||||||
|
resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa-bodyparser@4.3.12:
|
||||||
|
resolution: {integrity: sha512-hKMmRMVP889gPIdLZmmtou/BijaU1tHPyMNmcK7FAHAdATnRcGQQy78EqTTxLH1D4FTsrxIzklAQCso9oGoebQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.15.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa-compose@3.2.8:
|
||||||
|
resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.15.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa@2.15.0:
|
||||||
|
resolution: {integrity: sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==}
|
||||||
|
dependencies:
|
||||||
|
'@types/accepts': 1.3.7
|
||||||
|
'@types/content-disposition': 0.5.8
|
||||||
|
'@types/cookies': 0.9.0
|
||||||
|
'@types/http-assert': 1.5.5
|
||||||
|
'@types/http-errors': 2.0.4
|
||||||
|
'@types/keygrip': 1.0.6
|
||||||
|
'@types/koa-compose': 3.2.8
|
||||||
|
'@types/node': 20.11.27
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/lodash-es@4.17.12:
|
/@types/lodash-es@4.17.12:
|
||||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4435,6 +4521,14 @@ packages:
|
||||||
- bluebird
|
- bluebird
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/cache-content-type@1.0.1:
|
||||||
|
resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==}
|
||||||
|
engines: {node: '>= 6.0.0'}
|
||||||
|
dependencies:
|
||||||
|
mime-types: 2.1.35
|
||||||
|
ylru: 1.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/caching-transform@4.0.0:
|
/caching-transform@4.0.0:
|
||||||
resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==}
|
resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -4663,6 +4757,20 @@ packages:
|
||||||
readable-stream: 2.3.8
|
readable-stream: 2.3.8
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/co-body@6.1.0:
|
||||||
|
resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==}
|
||||||
|
dependencies:
|
||||||
|
inflation: 2.1.0
|
||||||
|
qs: 6.11.0
|
||||||
|
raw-body: 2.5.2
|
||||||
|
type-is: 1.6.18
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/co@4.6.0:
|
||||||
|
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
||||||
|
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/code-point@1.1.0:
|
/code-point@1.1.0:
|
||||||
resolution: {integrity: sha512-L9JOfOolA/Y/YKVO+WUscMXuYUcHmkleTJkvl1G0XaGFj5JDXl02BobH8avoI/pjWvgOLivs2bizA0N6g8gM9Q==}
|
resolution: {integrity: sha512-L9JOfOolA/Y/YKVO+WUscMXuYUcHmkleTJkvl1G0XaGFj5JDXl02BobH8avoI/pjWvgOLivs2bizA0N6g8gM9Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -4860,6 +4968,10 @@ packages:
|
||||||
typedarray: 0.0.6
|
typedarray: 0.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/config-ini-parser@1.6.1:
|
||||||
|
resolution: {integrity: sha512-6YBVmXlWiUKDhjn+S/1ju2+8j8Qnj1PqR8yE5DmLrQRtBOc9kgMLyutFl2so1FNVHevR/A4nY7z9EWw8s6g/Cw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/connect-history-api-fallback@2.0.0:
|
/connect-history-api-fallback@2.0.0:
|
||||||
resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==}
|
resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
@ -4891,6 +5003,14 @@ packages:
|
||||||
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
/cookies@0.9.1:
|
||||||
|
resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
depd: 2.0.0
|
||||||
|
keygrip: 1.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/core-js-compat@3.36.0:
|
/core-js-compat@3.36.0:
|
||||||
resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==}
|
resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -5415,6 +5535,10 @@ packages:
|
||||||
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
|
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/deep-equal@1.0.1:
|
||||||
|
resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/deep-is@0.1.4:
|
/deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -7218,7 +7342,6 @@ packages:
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/has-unicode@2.0.1:
|
/has-unicode@2.0.1:
|
||||||
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
||||||
|
@ -7332,6 +7455,14 @@ packages:
|
||||||
entities: 2.2.0
|
entities: 2.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/http-assert@1.5.0:
|
||||||
|
resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
deep-equal: 1.0.1
|
||||||
|
http-errors: 1.8.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/http-cache-semantics@4.1.1:
|
/http-cache-semantics@4.1.1:
|
||||||
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -7348,6 +7479,17 @@ packages:
|
||||||
setprototypeof: 1.1.0
|
setprototypeof: 1.1.0
|
||||||
statuses: 1.5.0
|
statuses: 1.5.0
|
||||||
|
|
||||||
|
/http-errors@1.8.1:
|
||||||
|
resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
depd: 1.1.2
|
||||||
|
inherits: 2.0.4
|
||||||
|
setprototypeof: 1.2.0
|
||||||
|
statuses: 1.5.0
|
||||||
|
toidentifier: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/http-errors@2.0.0:
|
/http-errors@2.0.0:
|
||||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -7505,6 +7647,11 @@ packages:
|
||||||
resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
|
resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/inflation@2.1.0:
|
||||||
|
resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/inflight@1.0.6:
|
/inflight@1.0.6:
|
||||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -7665,6 +7812,13 @@ packages:
|
||||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
/is-generator-function@1.0.10:
|
||||||
|
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-glob@3.1.0:
|
/is-glob@3.1.0:
|
||||||
resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==}
|
resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -8193,6 +8347,13 @@ packages:
|
||||||
resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==}
|
resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/keygrip@1.1.0:
|
||||||
|
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
tsscmp: 1.0.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
/keyv@4.5.4:
|
/keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -8211,6 +8372,49 @@ packages:
|
||||||
resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==}
|
resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/koa-compose@4.1.0:
|
||||||
|
resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/koa-convert@2.0.0:
|
||||||
|
resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
dependencies:
|
||||||
|
co: 4.6.0
|
||||||
|
koa-compose: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/koa@2.15.0:
|
||||||
|
resolution: {integrity: sha512-KEL/vU1knsoUvfP4MC4/GthpQrY/p6dzwaaGI6Rt4NQuFqkw3qrvsdYF5pz3wOfi7IGTvMPHC9aZIcUKYFNxsw==}
|
||||||
|
engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4}
|
||||||
|
dependencies:
|
||||||
|
accepts: 1.3.8
|
||||||
|
cache-content-type: 1.0.1
|
||||||
|
content-disposition: 0.5.4
|
||||||
|
content-type: 1.0.5
|
||||||
|
cookies: 0.9.1
|
||||||
|
debug: 4.3.4
|
||||||
|
delegates: 1.0.0
|
||||||
|
depd: 2.0.0
|
||||||
|
destroy: 1.2.0
|
||||||
|
encodeurl: 1.0.2
|
||||||
|
escape-html: 1.0.3
|
||||||
|
fresh: 0.5.2
|
||||||
|
http-assert: 1.5.0
|
||||||
|
http-errors: 1.8.1
|
||||||
|
is-generator-function: 1.0.10
|
||||||
|
koa-compose: 4.1.0
|
||||||
|
koa-convert: 2.0.0
|
||||||
|
on-finished: 2.4.1
|
||||||
|
only: 0.0.2
|
||||||
|
parseurl: 1.3.3
|
||||||
|
statuses: 1.5.0
|
||||||
|
type-is: 1.6.18
|
||||||
|
vary: 1.1.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
/kuler@2.0.0:
|
/kuler@2.0.0:
|
||||||
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
|
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -9138,6 +9342,10 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn: 2.1.0
|
mimic-fn: 2.1.0
|
||||||
|
|
||||||
|
/only@0.0.2:
|
||||||
|
resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/open@10.1.0:
|
/open@10.1.0:
|
||||||
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
@ -12033,6 +12241,11 @@ packages:
|
||||||
/tslib@2.6.2:
|
/tslib@2.6.2:
|
||||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||||
|
|
||||||
|
/tsscmp@1.0.6:
|
||||||
|
resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
|
||||||
|
engines: {node: '>=0.6.x'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ttf2eot@3.1.0:
|
/ttf2eot@3.1.0:
|
||||||
resolution: {integrity: sha512-aHTbcYosNHVqb2Qtt9Xfta77ae/5y0VfdwNLUS6sGBeGr22cX2JDMo/i5h3uuOf+FAD3akYOr17+fYd5NK8aXw==}
|
resolution: {integrity: sha512-aHTbcYosNHVqb2Qtt9Xfta77ae/5y0VfdwNLUS6sGBeGr22cX2JDMo/i5h3uuOf+FAD3akYOr17+fYd5NK8aXw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -12972,6 +13185,11 @@ packages:
|
||||||
fd-slicer: 1.1.0
|
fd-slicer: 1.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ylru@1.3.2:
|
||||||
|
resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==}
|
||||||
|
engines: {node: '>= 4.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/yn@3.1.1:
|
/yn@3.1.1:
|
||||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
|
@ -177,6 +177,9 @@ class zulip::app_frontend_base {
|
||||||
include zulip::smokescreen
|
include zulip::smokescreen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$katex_server = zulipconf('application_server', 'katex_server', false)
|
||||||
|
$katex_server_port = zulipconf('application_server', 'katex_server_port', '9700')
|
||||||
|
|
||||||
if $proxy_host != '' and $proxy_port != '' {
|
if $proxy_host != '' and $proxy_port != '' {
|
||||||
$proxy = "http://${proxy_host}:${proxy_port}"
|
$proxy = "http://${proxy_host}:${proxy_port}"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -106,6 +106,23 @@ programs=<% @queues.each_with_index do |queue, i| -%>zulip_events_<%= queue %><%
|
||||||
programs=zulip_events
|
programs=zulip_events
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<% if @katex_server %>
|
||||||
|
[program:zulip-katex]
|
||||||
|
command=/usr/local/bin/secret-env-wrapper SHARED_SECRET=shared_secret /srv/zulip-node/bin/node /home/zulip/deployments/current/static/webpack-bundles/katex_server.js <%= @katex_server_port %>
|
||||||
|
environment=NODE_ENV=production
|
||||||
|
priority=200 ; the relative start priority (default 999)
|
||||||
|
autostart=true ; start at supervisord start (default: true)
|
||||||
|
autorestart=true ; whether/when to restart (default: unexpected)
|
||||||
|
stopsignal=TERM ; signal used to kill process (default TERM)
|
||||||
|
stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
||||||
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
|
stdout_logfile=/var/log/zulip/katex.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=20MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=3 ; # of stdout logfile backups (default 10)
|
||||||
|
directory=/home/zulip/deployments/current/
|
||||||
|
<% end %>
|
||||||
|
|
||||||
; The [include] section can just contain the "files" setting. This
|
; The [include] section can just contain the "files" setting. This
|
||||||
; setting can list multiple files (separated by whitespace or
|
; setting can list multiple files (separated by whitespace or
|
||||||
; newlines). It can also contain wildcards. The filenames are
|
; newlines). It can also contain wildcards. The filenames are
|
||||||
|
|
|
@ -101,12 +101,17 @@ if has_application_server():
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# This is an optional service, so may or may not exist
|
||||||
|
workers.extend(list_supervisor_processes(["zulip-katex"]))
|
||||||
|
|
||||||
if has_process_fts_updates():
|
if has_process_fts_updates():
|
||||||
workers.append("process-fts-updates")
|
workers.append("process-fts-updates")
|
||||||
|
|
||||||
# Before we start (re)starting main services, make sure to start any
|
# Before we start (re)starting main services, make sure to start any
|
||||||
# optional auxiliary services that we don't stop, but do expect to be
|
# optional auxiliary services that we don't stop, but do expect to be
|
||||||
# running, and aren't currently.
|
# running, and aren't currently. These get new versions by getting
|
||||||
|
# updated supervisor files, and puppet restarts them -- so we never
|
||||||
|
# restart them in here, only start them.
|
||||||
aux_services = list_supervisor_processes(["go-camo", "smokescreen"], only_running=False)
|
aux_services = list_supervisor_processes(["go-camo", "smokescreen"], only_running=False)
|
||||||
if aux_services:
|
if aux_services:
|
||||||
subprocess.check_call(["supervisorctl", "start", *aux_services])
|
subprocess.check_call(["supervisorctl", "start", *aux_services])
|
||||||
|
|
|
@ -48,6 +48,6 @@ cp -a \
|
||||||
PNPM="/usr/local/bin/pnpm"
|
PNPM="/usr/local/bin/pnpm"
|
||||||
tar -C /tmp -xzf /tmp/production-build/zulip-server-test.tar.gz zulip-server-test/prod-static/serve/webpack-bundles
|
tar -C /tmp -xzf /tmp/production-build/zulip-server-test.tar.gz zulip-server-test/prod-static/serve/webpack-bundles
|
||||||
(
|
(
|
||||||
GLOBIGNORE=/tmp/zulip-server-test/prod-static/serve/webpack-bundles/katex-cli.js
|
GLOBIGNORE="/tmp/zulip-server-test/prod-static/serve/webpack-bundles/katex*.js"
|
||||||
"$PNPM" exec es-check es2020 /tmp/zulip-server-test/prod-static/serve/webpack-bundles/*.js
|
"$PNPM" exec es-check es2020 /tmp/zulip-server-test/prod-static/serve/webpack-bundles/*.js
|
||||||
)
|
)
|
||||||
|
|
|
@ -46,7 +46,7 @@ def build_for_dev_server(host: str, port: str, minify: bool, disable_host_check:
|
||||||
webpack_args = ["../node_modules/.bin/webpack-cli", "serve"]
|
webpack_args = ["../node_modules/.bin/webpack-cli", "serve"]
|
||||||
webpack_args += [
|
webpack_args += [
|
||||||
# webpack-cli has a bug where it ignores --watch-poll with
|
# webpack-cli has a bug where it ignores --watch-poll with
|
||||||
# multi-config, and we don't need the katex-cli part anyway.
|
# multi-config, and we don't need the katex part anyway.
|
||||||
"--config-name=frontend",
|
"--config-name=frontend",
|
||||||
f"--host={host}",
|
f"--host={host}",
|
||||||
f"--port={port}",
|
f"--port={port}",
|
||||||
|
|
|
@ -48,4 +48,4 @@ API_FEATURE_LEVEL = 243
|
||||||
# historical commits sharing the same major version, in which case a
|
# historical commits sharing the same major version, in which case a
|
||||||
# minor version bump suffices.
|
# minor version bump suffices.
|
||||||
|
|
||||||
PROVISION_VERSION = (264, 3)
|
PROVISION_VERSION = (264, 4)
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
|
import bodyParser from "@koa/bodyparser";
|
||||||
|
import katex from "katex";
|
||||||
|
import Koa from "koa";
|
||||||
|
|
||||||
|
const host = "localhost";
|
||||||
|
const port = Number(process.argv[2] ?? "9700");
|
||||||
|
if (!Number.isInteger(port)) {
|
||||||
|
throw new TypeError("Invalid port");
|
||||||
|
}
|
||||||
|
|
||||||
|
const shared_secret = process.env.SHARED_SECRET;
|
||||||
|
if (typeof shared_secret !== "string") {
|
||||||
|
console.error("No SHARED_SECRET set!");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const compare_secret = (given_secret: string): boolean => {
|
||||||
|
try {
|
||||||
|
// Throws an exception if the strings are unequal length
|
||||||
|
return crypto.timingSafeEqual(
|
||||||
|
Buffer.from(shared_secret, "utf8"),
|
||||||
|
Buffer.from(given_secret, "utf8"),
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const app = new Koa();
|
||||||
|
app.use(bodyParser());
|
||||||
|
|
||||||
|
app.use((ctx, _next) => {
|
||||||
|
if (ctx.request.method !== "POST" || ctx.request.path !== "/") {
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx.request.body === undefined) {
|
||||||
|
ctx.status = 400;
|
||||||
|
ctx.type = "text/plain";
|
||||||
|
ctx.body = "Missing POST body";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const given_secret = ctx.request.body.shared_secret;
|
||||||
|
if (typeof given_secret !== "string" || !compare_secret(given_secret)) {
|
||||||
|
ctx.status = 403;
|
||||||
|
ctx.type = "text/plain";
|
||||||
|
ctx.body = "Invalid 'shared_secret' argument";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = ctx.request.body.content;
|
||||||
|
const is_display = ctx.request.body.is_display === "true";
|
||||||
|
|
||||||
|
if (typeof content !== "string") {
|
||||||
|
ctx.status = 400;
|
||||||
|
ctx.type = "text/plain";
|
||||||
|
ctx.body = "Invalid 'content' argument";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctx.body = katex.renderToString(content, {displayMode: is_display});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof katex.ParseError) {
|
||||||
|
ctx.status = 400;
|
||||||
|
ctx.type = "text/plain";
|
||||||
|
ctx.body = error.message;
|
||||||
|
} else {
|
||||||
|
ctx.status = 500;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, host, () => {
|
||||||
|
console.log(`Server started on http://${host}:${port}`);
|
||||||
|
});
|
|
@ -255,11 +255,18 @@ export default (
|
||||||
name: "server",
|
name: "server",
|
||||||
target: "node",
|
target: "node",
|
||||||
entry: {
|
entry: {
|
||||||
|
katex_server: "babel-loader!./server/katex_server.ts",
|
||||||
"katex-cli": "shebang-loader!katex/cli",
|
"katex-cli": "shebang-loader!katex/cli",
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "../static/webpack-bundles"),
|
path: path.resolve(__dirname, "../static/webpack-bundles"),
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
// koa-body uses formidable 2.x, which suffers from https://github.com/node-formidable/formidable/issues/337
|
||||||
|
hexoid: "hexoid/dist/index.js",
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return [frontendConfig, serverConfig];
|
return [frontendConfig, serverConfig];
|
||||||
|
|
|
@ -1,14 +1,24 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import lxml.html
|
import lxml.html
|
||||||
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
from zerver.lib.outgoing_http import OutgoingSession
|
||||||
from zerver.lib.storage import static_path
|
from zerver.lib.storage import static_path
|
||||||
|
|
||||||
|
|
||||||
|
class KatexSession(OutgoingSession):
|
||||||
|
def __init__(self, **kwargs: Any) -> None:
|
||||||
|
# We set a very short timeout because these requests are
|
||||||
|
# expected to be quite fast (milliseconds) and blocking on
|
||||||
|
# this affects message rendering performance.
|
||||||
|
super().__init__(role="katex", timeout=0.5, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def render_tex(tex: str, is_inline: bool = True) -> Optional[str]:
|
def render_tex(tex: str, is_inline: bool = True) -> Optional[str]:
|
||||||
r"""Render a TeX string into HTML using KaTeX
|
r"""Render a TeX string into HTML using KaTeX
|
||||||
|
|
||||||
|
@ -23,6 +33,38 @@ def render_tex(tex: str, is_inline: bool = True) -> Optional[str]:
|
||||||
(default True)
|
(default True)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if settings.KATEX_SERVER:
|
||||||
|
try:
|
||||||
|
resp = KatexSession().post(
|
||||||
|
# We explicitly disable the Smokescreen proxy for this
|
||||||
|
# call, since it intentionally connects to localhost.
|
||||||
|
# This is safe because the host is explicitly fixed, and
|
||||||
|
# the port is pulled from our own configuration.
|
||||||
|
f"http://localhost:{settings.KATEX_SERVER_PORT}/",
|
||||||
|
data={
|
||||||
|
"content": tex,
|
||||||
|
"is_display": "false" if is_inline else "true",
|
||||||
|
"shared_secret": settings.SHARED_SECRET,
|
||||||
|
},
|
||||||
|
proxies={"http": ""},
|
||||||
|
)
|
||||||
|
except requests.exceptions.Timeout:
|
||||||
|
logging.warning("KaTeX rendering service timed out with %d byte long input", len(tex))
|
||||||
|
return None
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.warning("KaTeX rendering service failed: %s", type(e).__name__)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if resp.status_code == 200:
|
||||||
|
return resp.content.decode().strip()
|
||||||
|
elif resp.status_code == 400:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
logging.warning(
|
||||||
|
"KaTeX rendering service failed: (%s) %s", resp.status_code, resp.content.decode()
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
katex_path = (
|
katex_path = (
|
||||||
static_path("webpack-bundles/katex-cli.js")
|
static_path("webpack-bundles/katex-cli.js")
|
||||||
if settings.PRODUCTION
|
if settings.PRODUCTION
|
||||||
|
|
|
@ -7,10 +7,13 @@ from typing import Any, Dict, List, Optional, Set, Tuple
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
|
import requests
|
||||||
|
import responses
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from markdown import Markdown
|
from markdown import Markdown
|
||||||
|
from responses import matchers
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from zerver.actions.alert_words import do_add_alert_words
|
from zerver.actions.alert_words import do_add_alert_words
|
||||||
|
@ -297,6 +300,79 @@ class MarkdownMiscTest(ZulipTestCase):
|
||||||
render_tex("random text")
|
render_tex("random text")
|
||||||
self.assertEqual(m.output, ["ERROR:root:Cannot find KaTeX for latex rendering!"])
|
self.assertEqual(m.output, ["ERROR:root:Cannot find KaTeX for latex rendering!"])
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
@override_settings(KATEX_SERVER=True, SHARED_SECRET="foo")
|
||||||
|
def test_katex_server(self) -> None:
|
||||||
|
responses.post(
|
||||||
|
"http://localhost:9700/",
|
||||||
|
match=[
|
||||||
|
matchers.urlencoded_params_matcher(
|
||||||
|
{"content": "foo", "is_display": "false", "shared_secret": "foo"}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
body="<i>html</i>",
|
||||||
|
)
|
||||||
|
self.assertEqual(render_tex("foo"), "<i>html</i>")
|
||||||
|
|
||||||
|
responses.post(
|
||||||
|
"http://localhost:9700/?",
|
||||||
|
match=[
|
||||||
|
matchers.urlencoded_params_matcher(
|
||||||
|
{"content": "foo", "is_display": "true", "shared_secret": "foo"}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
body="<i>other</i>",
|
||||||
|
)
|
||||||
|
self.assertEqual(render_tex("foo", is_inline=False), "<i>other</i>")
|
||||||
|
|
||||||
|
responses.post(
|
||||||
|
"http://localhost:9700/",
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
status=400,
|
||||||
|
body=r"KaTeX parse error: '\'",
|
||||||
|
)
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
|
||||||
|
responses.post(
|
||||||
|
"http://localhost:9700/",
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
status=400,
|
||||||
|
body=r"KaTeX parse error: '\'",
|
||||||
|
)
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
|
||||||
|
responses.post("http://localhost:9700/", status=403, body="")
|
||||||
|
with self.assertLogs(level="WARNING") as m:
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
self.assertEqual(m.output, ["WARNING:root:KaTeX rendering service failed: (403) "])
|
||||||
|
|
||||||
|
responses.post("http://localhost:9700/", status=500, body="")
|
||||||
|
with self.assertLogs(level="WARNING") as m:
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
self.assertEqual(m.output, ["WARNING:root:KaTeX rendering service failed: (500) "])
|
||||||
|
|
||||||
|
responses.post("http://localhost:9700/", body=requests.exceptions.Timeout())
|
||||||
|
with self.assertLogs(level="WARNING") as m:
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
self.assertEqual(
|
||||||
|
m.output, ["WARNING:root:KaTeX rendering service timed out with 3 byte long input"]
|
||||||
|
)
|
||||||
|
|
||||||
|
responses.post("http://localhost:9700/", body=requests.exceptions.ConnectionError())
|
||||||
|
with self.assertLogs(level="WARNING") as m:
|
||||||
|
self.assertEqual(render_tex("bad"), None)
|
||||||
|
self.assertEqual(m.output, ["WARNING:root:KaTeX rendering service failed: ConnectionError"])
|
||||||
|
|
||||||
|
with override_settings(KATEX_SERVER_PORT=9701):
|
||||||
|
responses.post(
|
||||||
|
"http://localhost:9701/",
|
||||||
|
body="<i>html</i>",
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
)
|
||||||
|
self.assertEqual(render_tex("foo"), "<i>html</i>")
|
||||||
|
|
||||||
|
|
||||||
class MarkdownListPreprocessorTest(ZulipTestCase):
|
class MarkdownListPreprocessorTest(ZulipTestCase):
|
||||||
# We test that the preprocessor inserts blank lines at correct places.
|
# We test that the preprocessor inserts blank lines at correct places.
|
||||||
|
|
|
@ -520,6 +520,14 @@ INTERNAL_BOT_DOMAIN = "zulip.com"
|
||||||
# This needs to be synced with the Camo installation
|
# This needs to be synced with the Camo installation
|
||||||
CAMO_KEY = get_secret("camo_key") if CAMO_URI != "" else None
|
CAMO_KEY = get_secret("camo_key") if CAMO_URI != "" else None
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# KATEX SERVER SETTINGS
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
KATEX_SERVER = get_config("application_server", "katex_server", False)
|
||||||
|
KATEX_SERVER_PORT = get_config("application_server", "katex_server_port", "9700")
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# STATIC CONTENT AND MINIFICATION SETTINGS
|
# STATIC CONTENT AND MINIFICATION SETTINGS
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
Loading…
Reference in New Issue