mirror of
https://gitlab.com/mangadex-pub/mangadex_at_home.git
synced 2024-01-19 02:48:37 +00:00
Remove webui part 2 redux electric bugaloo
This commit is contained in:
parent
9896a8be6a
commit
0266f5d451
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -104,7 +104,7 @@ gradle-app.setting
|
|||
nbproject/**
|
||||
|
||||
log/**
|
||||
cache/**
|
||||
|
||||
images/**
|
||||
*.db
|
||||
|
||||
settings.json
|
|
@ -49,7 +49,7 @@ object ServerHandlerJackson : ConfigurableJackson(
|
|||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
)
|
||||
|
||||
class ServerHandler(
|
||||
class BackendApi(
|
||||
private val serverSettings: ServerSettings,
|
||||
private val devSettings: DevSettings,
|
||||
private val maxCacheSizeInMebibytes: Long
|
||||
|
@ -136,7 +136,7 @@ class ServerHandler(
|
|||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LoggerFactory.getLogger(ServerHandler::class.java)
|
||||
private val LOGGER = LoggerFactory.getLogger(BackendApi::class.java)
|
||||
private val STRING_ANY_MAP_LENS = Body.auto<Map<String, Any>>().toLens()
|
||||
private val SERVER_SETTINGS_LENS = Body.auto<RemoteSettings>().toLens()
|
||||
private const val SERVER_ADDRESS = "https://api.mangadex.network/"
|
||||
|
|
|
@ -55,10 +55,10 @@ object Main {
|
|||
data class ClientArgs(
|
||||
@field:CommandLine.Option(names = ["-s", "--settings"], defaultValue = "settings.json", paramLabel = "<settings>", description = ["the settings file (default: \${DEFAULT-VALUE})"])
|
||||
var settingsFile: File = File("settings.json"),
|
||||
@field:CommandLine.Option(names = ["-d", "--database"], defaultValue = ".\${sys:file.separator}data", paramLabel = "<settings>", description = ["the database file (default: \${DEFAULT-VALUE})"])
|
||||
var databaseFile: File = File(".${File.separator}data"),
|
||||
@field:CommandLine.Option(names = ["-c", "--cache"], defaultValue = "cache", paramLabel = "<settings>", description = ["the cache folder (default: \${DEFAULT-VALUE})"])
|
||||
var cacheFolder: Path = Paths.get("cache"),
|
||||
@field:CommandLine.Option(names = ["-d", "--database"], defaultValue = ".\${sys:file.separator}metadata", paramLabel = "<settings>", description = ["the database file (default: \${DEFAULT-VALUE})"])
|
||||
var databaseFile: File = File(".${File.separator}metadata"),
|
||||
@field:CommandLine.Option(names = ["-c", "--cache"], defaultValue = "images", paramLabel = "<settings>", description = ["the cache folder (default: \${DEFAULT-VALUE})"])
|
||||
var cacheFolder: Path = Paths.get("images"),
|
||||
@field:CommandLine.Option(names = ["-h", "--help"], usageHelp = true, description = ["show this help message and exit"])
|
||||
var helpRequested: Boolean = false,
|
||||
@field:CommandLine.Option(names = ["-v", "--version"], versionHelp = true, description = ["show the version message and exit"])
|
||||
|
|
|
@ -29,7 +29,6 @@ import mdnet.Main.dieWithError
|
|||
import mdnet.cache.ImageStorage
|
||||
import mdnet.logging.info
|
||||
import mdnet.logging.warn
|
||||
import mdnet.server.getUiServer
|
||||
import mdnet.settings.ClientSettings
|
||||
import org.http4k.server.Http4kServer
|
||||
import org.ktorm.database.Database
|
||||
|
@ -58,7 +57,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
|
||||
// state that must only be accessed from the thread on the executor
|
||||
private var imageServer: ServerManager? = null
|
||||
private var webUi: Http4kServer? = null
|
||||
// end protected state
|
||||
|
||||
init {
|
||||
|
@ -88,7 +86,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
LOGGER.info { "Mangadex@Home Client initialized - starting normal operation" }
|
||||
|
||||
startImageServer()
|
||||
startWebUi()
|
||||
|
||||
scheduledFuture = executor.scheduleWithFixedDelay(
|
||||
{
|
||||
|
@ -103,22 +100,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
)
|
||||
}
|
||||
|
||||
// Precondition: settings must be filled with up-to-date settings and `imageServer` must not be null
|
||||
private fun startWebUi() {
|
||||
settings.webSettings?.let { webSettings ->
|
||||
val imageServer = requireNotNull(imageServer)
|
||||
|
||||
if (webUi != null) {
|
||||
throw AssertionError()
|
||||
}
|
||||
LOGGER.info { "WebUI starting" }
|
||||
webUi = getUiServer(webSettings, imageServer.statistics, imageServer.statsMap).also {
|
||||
it.start()
|
||||
}
|
||||
LOGGER.info { "WebUI started" }
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition: settings must be filled with up-to-date settings
|
||||
private fun startImageServer() {
|
||||
if (imageServer != null) {
|
||||
|
@ -131,13 +112,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
LOGGER.info { "Server manager started" }
|
||||
}
|
||||
|
||||
private fun stopWebUi() {
|
||||
LOGGER.info { "WebUI stopping" }
|
||||
requireNotNull(webUi).stop()
|
||||
webUi = null
|
||||
LOGGER.info { "WebUI stopped" }
|
||||
}
|
||||
|
||||
private fun stopImageServer() {
|
||||
LOGGER.info { "Server manager stopping" }
|
||||
requireNotNull(imageServer).shutdown()
|
||||
|
@ -153,9 +127,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
|
||||
executor.schedule(
|
||||
{
|
||||
if (webUi != null) {
|
||||
stopWebUi()
|
||||
}
|
||||
if (imageServer != null) {
|
||||
stopImageServer()
|
||||
}
|
||||
|
@ -193,25 +164,11 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
val restartServer = newSettings.serverSettings != settings.serverSettings ||
|
||||
newSettings.devSettings != settings.devSettings
|
||||
|
||||
val stopWebUi = restartServer || newSettings.webSettings != settings.webSettings
|
||||
val startWebUi = stopWebUi && newSettings.webSettings != null
|
||||
|
||||
if (stopWebUi) {
|
||||
LOGGER.info { "Stopping WebUI to reload ClientSettings" }
|
||||
if (webUi != null) {
|
||||
stopWebUi()
|
||||
}
|
||||
}
|
||||
|
||||
if (restartServer) {
|
||||
stopImageServer()
|
||||
startImageServer()
|
||||
}
|
||||
|
||||
if (startWebUi) {
|
||||
startWebUi()
|
||||
}
|
||||
|
||||
settings = newSettings
|
||||
} catch (e: UnrecognizedPropertyException) {
|
||||
LOGGER.warn { "Settings file is invalid: '$e.propertyName' is not a valid setting" }
|
||||
|
@ -256,11 +213,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
throw ClientSettingsException("Config Error: Graceful shutdown wait must be >= 15")
|
||||
}
|
||||
}
|
||||
settings.webSettings?.let {
|
||||
if (it.port == 0) {
|
||||
throw ClientSettingsException("Config Error: Invalid UI port number")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun readClientSettings(): ClientSettings {
|
||||
|
|
|
@ -55,7 +55,7 @@ class ServerManager(serverSettings: ServerSettings, devSettings: DevSettings, ma
|
|||
|
||||
// state that must only be accessed from the thread on the executor
|
||||
private var state: State
|
||||
private var serverHandler: ServerHandler
|
||||
private var backendApi: BackendApi
|
||||
// end protected state
|
||||
|
||||
val statsMap: MutableMap<Instant, Statistics> = Collections
|
||||
|
@ -72,7 +72,7 @@ class ServerManager(serverSettings: ServerSettings, devSettings: DevSettings, ma
|
|||
|
||||
init {
|
||||
state = Uninitialized(serverSettings, devSettings)
|
||||
serverHandler = ServerHandler(serverSettings, devSettings, maxCacheSizeInMebibytes)
|
||||
backendApi = BackendApi(serverSettings, devSettings, maxCacheSizeInMebibytes)
|
||||
|
||||
// storage.get("statistics")?.use {
|
||||
// try {
|
||||
|
@ -212,7 +212,7 @@ class ServerManager(serverSettings: ServerSettings, devSettings: DevSettings, ma
|
|||
}
|
||||
|
||||
val state = this.state as Running
|
||||
val newSettings = serverHandler.pingControl(state.settings)
|
||||
val newSettings = backendApi.pingControl(state.settings)
|
||||
|
||||
if (newSettings != null) {
|
||||
LOGGER.info { "Server settings received: $newSettings" }
|
||||
|
@ -233,7 +233,7 @@ class ServerManager(serverSettings: ServerSettings, devSettings: DevSettings, ma
|
|||
private fun loginAndStartServer() {
|
||||
val state = this.state as Uninitialized
|
||||
|
||||
val remoteSettings = serverHandler.loginToControl()
|
||||
val remoteSettings = backendApi.loginToControl()
|
||||
?: throw RuntimeException("Failed to get a login response from server")
|
||||
LOGGER.info { "Server settings received: $remoteSettings" }
|
||||
warmBasedOnSettings(remoteSettings)
|
||||
|
@ -245,7 +245,7 @@ class ServerManager(serverSettings: ServerSettings, devSettings: DevSettings, ma
|
|||
}
|
||||
|
||||
private fun logout() {
|
||||
serverHandler.logoutFromControl()
|
||||
backendApi.logoutFromControl()
|
||||
}
|
||||
|
||||
private fun stopServer(nextState: State) {
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Mangadex@Home
|
||||
Copyright (c) 2020, MangaDex Network
|
||||
This file is part of MangaDex@Home.
|
||||
|
||||
MangaDex@Home is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MangaDex@Home is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this MangaDex@Home. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package mdnet.netty
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
import io.netty.channel.ChannelFactory
|
||||
import io.netty.channel.ChannelFuture
|
||||
import io.netty.channel.ChannelInitializer
|
||||
import io.netty.channel.ChannelOption
|
||||
import io.netty.channel.ServerChannel
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator
|
||||
import io.netty.handler.codec.http.HttpServerCodec
|
||||
import io.netty.handler.codec.http.HttpServerKeepAliveHandler
|
||||
import io.netty.handler.stream.ChunkedWriteHandler
|
||||
import org.http4k.core.HttpHandler
|
||||
import org.http4k.server.Http4kChannelHandler
|
||||
import org.http4k.server.Http4kServer
|
||||
import org.http4k.server.ServerConfig
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
class WebUiNetty(private val hostname: String, private val port: Int) : ServerConfig {
|
||||
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
|
||||
private val masterGroup = NioEventLoopGroup()
|
||||
private val workerGroup = NioEventLoopGroup()
|
||||
private lateinit var closeFuture: ChannelFuture
|
||||
private lateinit var address: InetSocketAddress
|
||||
|
||||
override fun start(): Http4kServer = apply {
|
||||
val bootstrap = ServerBootstrap()
|
||||
bootstrap.group(masterGroup, workerGroup)
|
||||
.channelFactory(ChannelFactory<ServerChannel> { NioServerSocketChannel() })
|
||||
.childHandler(object : ChannelInitializer<SocketChannel>() {
|
||||
public override fun initChannel(ch: SocketChannel) {
|
||||
ch.pipeline().addLast("codec", HttpServerCodec())
|
||||
ch.pipeline().addLast("keepAlive", HttpServerKeepAliveHandler())
|
||||
ch.pipeline().addLast("aggregator", HttpObjectAggregator(Int.MAX_VALUE))
|
||||
ch.pipeline().addLast("streamer", ChunkedWriteHandler())
|
||||
ch.pipeline().addLast("handler", Http4kChannelHandler(httpHandler))
|
||||
}
|
||||
})
|
||||
.option(ChannelOption.SO_BACKLOG, 1000)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||
|
||||
val channel = bootstrap.bind(InetSocketAddress(hostname, port)).sync().channel()
|
||||
address = channel.localAddress() as InetSocketAddress
|
||||
closeFuture = channel.closeFuture()
|
||||
}
|
||||
|
||||
override fun stop() = apply {
|
||||
closeFuture.cancel(false)
|
||||
workerGroup.shutdownGracefully()
|
||||
masterGroup.shutdownGracefully()
|
||||
}
|
||||
|
||||
override fun port(): Int = address.port
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Mangadex@Home
|
||||
Copyright (c) 2020, MangaDex Network
|
||||
This file is part of MangaDex@Home.
|
||||
|
||||
MangaDex@Home is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MangaDex@Home is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this MangaDex@Home. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* ktlint-disable no-wildcard-imports */
|
||||
package mdnet.server
|
||||
|
||||
import mdnet.data.Statistics
|
||||
import mdnet.netty.WebUiNetty
|
||||
import mdnet.settings.WebSettings
|
||||
import org.http4k.core.Body
|
||||
import org.http4k.core.Method
|
||||
import org.http4k.core.Response
|
||||
import org.http4k.core.Status
|
||||
import org.http4k.core.then
|
||||
import org.http4k.format.Jackson.auto
|
||||
import org.http4k.routing.ResourceLoader
|
||||
import org.http4k.routing.bind
|
||||
import org.http4k.routing.routes
|
||||
import org.http4k.routing.singlePageApp
|
||||
import org.http4k.server.Http4kServer
|
||||
import org.http4k.server.asServer
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
fun getUiServer(
|
||||
webSettings: WebSettings,
|
||||
statistics: AtomicReference<Statistics>,
|
||||
statsMap: Map<Instant, Statistics>
|
||||
): Http4kServer {
|
||||
val statsMapLens = Body.auto<Map<Instant, Statistics>>().toLens()
|
||||
|
||||
return catchAllHideDetails()
|
||||
.then(addCommonHeaders())
|
||||
.then(
|
||||
routes(
|
||||
"/api/stats" bind Method.GET to {
|
||||
statsMapLens(mapOf(Instant.now() to statistics.get()), Response(Status.OK))
|
||||
},
|
||||
"/api/pastStats" bind Method.GET to {
|
||||
synchronized(statsMap) {
|
||||
statsMapLens(statsMap, Response(Status.OK))
|
||||
}
|
||||
},
|
||||
singlePageApp(ResourceLoader.Classpath("/webui"))
|
||||
)
|
||||
)
|
||||
.asServer(WebUiNetty(webSettings.hostname, webSettings.port))
|
||||
}
|
|
@ -26,7 +26,6 @@ import dev.afanasev.sekret.Secret
|
|||
data class ClientSettings(
|
||||
val maxCacheSizeInMebibytes: Long = 20480,
|
||||
val devSettings: DevSettings = DevSettings(),
|
||||
val webSettings: WebSettings? = null,
|
||||
val serverSettings: ServerSettings = ServerSettings(),
|
||||
)
|
||||
|
||||
|
@ -42,12 +41,6 @@ data class ServerSettings(
|
|||
val threads: Int = 4,
|
||||
)
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
data class WebSettings(
|
||||
val hostname: String = "127.0.0.1",
|
||||
val port: Int = 8080
|
||||
)
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
data class DevSettings(
|
||||
val devUrl: String? = null
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.vue-resizable-handle{background-image:none!important}.xterm{font-feature-settings:"liga" 0;position:relative;-moz-user-select:none;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm{cursor:text}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:.5}.xterm-underline{text-decoration:underline}.xterm ::-webkit-scrollbar{width:7px}.xterm ::-webkit-scrollbar-track{background-color:transparent}.xterm ::-webkit-scrollbar-thumb{background-color:#fff}
|
|
@ -1 +0,0 @@
|
|||
.echarts{width:600px;height:400px}
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 215 B |
|
@ -1 +0,0 @@
|
|||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="favicon.ico"><![endif]--><title>MD@H Client</title><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css><script src=https://cdn.jsdelivr.net/npm/echarts@4.1.0/dist/echarts.js></script><script src=https://cdn.jsdelivr.net/npm/vue-echarts@4.0.2></script><script src=https://unpkg.com/xterm@4.0.0/lib/xterm.js></script><link rel=text/css href=node_modules/xterm/css/xterm.css><link href=css/chunk-7577183e.6dc57fe0.css rel=prefetch><link href=js/chunk-7577183e.d6d29bcc.js rel=prefetch><link href=css/app.14a6e628.css rel=preload as=style><link href=css/chunk-vendors.b02cf67a.css rel=preload as=style><link href=js/app.ede7edb7.js rel=preload as=script><link href=js/chunk-vendors.1256013f.js rel=preload as=script><link href=css/chunk-vendors.b02cf67a.css rel=stylesheet><link href=css/app.14a6e628.css rel=stylesheet><link rel=icon type=image/png sizes=32x32 href=img/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=img/icons/favicon-16x16.png><link rel=manifest href=manifest.json><meta name=theme-color content=#f79421><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-status-bar-style content=black><meta name=apple-mobile-web-app-title content="MD@H Client Interface"><link rel=apple-touch-icon href=img/icons/apple-touch-icon-152x152.png><link rel=mask-icon href=img/icons/safari-pinned-tab.svg color=#f79421><meta name=msapplication-TileImage content=img/icons/msapplication-icon-144x144.png><meta name=msapplication-TileColor content=#000000></head><body style="overflow: hidden"><noscript><div style="background-color: #0980e8; position: absolute; top: 0; left: 0; width: 100%; height: 100%; user-select: none"><div style="position: absolute; top: 15%; left: 20%; width: 60%; font-family: Segoe UI; color: white;"><p style="font-size: 180px; margin: 0">:(</p><p style="font-size: 30px; margin-top: 50px">It appears that you don't have javascript enabled.<br>This isn't a big deal, but it just means that you've killed my wonderful web UI.<br>How evil of you...</p><p style="font-size: 10px; margin-top: 10px">Really though ;-;<br>I put in a lot of work and I'm very sad that you choose to disable the one thing that I needed :/</p></div></div></noscript><div id=app></div><script src=js/chunk-vendors.1256013f.js></script><script src=js/app.ede7edb7.js></script></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
{"name":"MD@H Client Interface","short_name":"MD@H","theme_color":"#f79421","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":"","display":"standalone","background_color":"#000000"}
|
|
@ -1,38 +0,0 @@
|
|||
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
||||
{
|
||||
"revision": "bb309837f2cf709edac5",
|
||||
"url": "css/app.14a6e628.css"
|
||||
},
|
||||
{
|
||||
"revision": "f9df31735412a9a525ef",
|
||||
"url": "css/chunk-7577183e.6dc57fe0.css"
|
||||
},
|
||||
{
|
||||
"revision": "027724770bde7ff56e58",
|
||||
"url": "css/chunk-vendors.b02cf67a.css"
|
||||
},
|
||||
{
|
||||
"revision": "7968686572fffa22fa9bdf28cc308706",
|
||||
"url": "index.html"
|
||||
},
|
||||
{
|
||||
"revision": "bb309837f2cf709edac5",
|
||||
"url": "js/app.ede7edb7.js"
|
||||
},
|
||||
{
|
||||
"revision": "f9df31735412a9a525ef",
|
||||
"url": "js/chunk-7577183e.d6d29bcc.js"
|
||||
},
|
||||
{
|
||||
"revision": "027724770bde7ff56e58",
|
||||
"url": "js/chunk-vendors.1256013f.js"
|
||||
},
|
||||
{
|
||||
"revision": "134416f208a045e960280cbf5c867e5c",
|
||||
"url": "manifest.json"
|
||||
},
|
||||
{
|
||||
"revision": "b6216d61c03e6ce0c9aea6ca7808f7ca",
|
||||
"url": "robots.txt"
|
||||
}
|
||||
]);
|
|
@ -1,2 +0,0 @@
|
|||
User-agent: *
|
||||
Disallow:
|
|
@ -1,3 +0,0 @@
|
|||
importScripts("precache-manifest.9917f0a006705c9b6b6c1abfab436c1f.js", "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
|
||||
|
||||
|
Loading…
Reference in a new issue