Оптимизация страниц. Начало реализации мультиплеера
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
static
|
static
|
||||||
|
server/toe
|
||||||
|
|||||||
69
generate.py
69
generate.py
@@ -13,8 +13,8 @@ if help_mode:
|
|||||||
print(f'Args:')
|
print(f'Args:')
|
||||||
print(f'\thelp - Show this message')
|
print(f'\thelp - Show this message')
|
||||||
print(f'\tfile - File mode with .html extension')
|
print(f'\tfile - File mode with .html extension')
|
||||||
print(f'\tserver - Server mode without .html extension for use folder as static files')
|
print(f'\tserver - Server mode without .html extension for use folder as static pages')
|
||||||
print(f'\t[path]/ - Directory for save files')
|
print(f'\t[path]/ - Directory for save pages')
|
||||||
exit(0)
|
exit(0)
|
||||||
else:
|
else:
|
||||||
if file_mode and server_mode:
|
if file_mode and server_mode:
|
||||||
@@ -39,12 +39,39 @@ def check_win(board) -> str:
|
|||||||
return next((board[line[0]] for line in lines if board[line[0]] == board[line[1]] == board[line[2]] != '-'), '-')
|
return next((board[line[0]] for line in lines if board[line[0]] == board[line[1]] == board[line[2]] != '-'), '-')
|
||||||
|
|
||||||
minify = lambda s: s.replace('\n', '').replace('\t', '').replace(' ', '')
|
minify = lambda s: s.replace('\n', '').replace('\t', '').replace(' ', '')
|
||||||
files = {
|
style = minify("""
|
||||||
'index':
|
body{margin:0;padding:20px;font-family:Arial,sans-serif;text-align:center;background:#fff}h1{font-size:24px;margin-bottom:20px}
|
||||||
minify(f"""{'<meta property="og:url" content="ToDo">' if server_mode else ''}<title>oxTicTacToe</title>
|
a{text-decoration:none}img{width:10vw}a,h1 a{color:#007bff}table{margin:0 auto;border-collapse:collapse;max-width:100%;overflow-x:auto}
|
||||||
<h1>oxTicTacToe.html</h1><p>Select team for start [ <a href="o---------.html">O</a> | <a href="x---------.html">X</a> ]</p>
|
td,td a{line-height:50px}td{border:1px solid #ccc;padding:10px;width:50px;height:50px;text-align:center;font-size:18px;vertical-align:middle}
|
||||||
<a href="https://git.0x174.su/wowlikon/oxTTT">source code</a><script src="s.js"></script>""")
|
td a{display:block;width:100%;height:100%;color:#007bff}td:hover{background:#eee}@media (max-width:600px){body{padding:10px}img{width:20vw}
|
||||||
|
h1{font-size:20px;margin-bottom:10px}td{padding:5px;width:40px;height:40px;font-size:16px}td,td a{line-height:40px}}""")
|
||||||
|
apply_css = minify(f"const style=document.createElement('style');style.textContent='{style}';document.head.appendChild(style);")
|
||||||
|
preload = minify("""
|
||||||
|
document.addEventListener('mouseover', e => {
|
||||||
|
const a = e.target.closest('a[href]');
|
||||||
|
if (!a) return;
|
||||||
|
if (!a.dataset.prefetched) {
|
||||||
|
a.dataset.prefetched = true;
|
||||||
|
fetch(a.href, {mode: 'no-cors'});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
""")
|
||||||
|
pages = {
|
||||||
|
'index':
|
||||||
|
minify(f"""<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<meta property="og:url" content="http://0x174.su/tic/tac/toe/index.html">
|
||||||
|
<title>oxTicTacToe</title><img src="/favicon.ico"><h1>oxTicTacToe.html</h1>
|
||||||
|
<p>Select team for start [ <a href="o---------.html">O</a> | <a href="x---------.html">X</a> ]
|
||||||
|
{'<br/><a href="../../../multiplayer">multiplayer mode</a>' if server_mode else ''}</p>
|
||||||
|
<a href="https://git.0x174.su/wowlikon/oxTTT">source code</a>
|
||||||
|
<script src="{'s' if file_mode else 'a'}.js"></script>""")
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts = {
|
||||||
|
's': apply_css,
|
||||||
|
'p': preload,
|
||||||
|
'a': (apply_css+preload)
|
||||||
|
}
|
||||||
|
|
||||||
try: iterable = tqdm(itertools.product('-xo', repeat=10))
|
try: iterable = tqdm(itertools.product('-xo', repeat=10))
|
||||||
except: iterable = itertools.product('-xo', repeat=10)
|
except: iterable = itertools.product('-xo', repeat=10)
|
||||||
@@ -61,8 +88,8 @@ for field_tuple in iterable:
|
|||||||
line = lambda n: "index.html"
|
line = lambda n: "index.html"
|
||||||
title = f'Draft'
|
title = f'Draft'
|
||||||
else: title = field[0]
|
else: title = field[0]
|
||||||
content = minify(f"""{'<meta property="og:url" content="ToDo">' if server_mode else ''}
|
content = minify(f"""<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>oxTTT:{title}</title><h1><a href="{line(0)}">{title}</a></h1>
|
<meta property="og:url" content="http://0x174.su/tic/tac/toe/{field}.html"><title>oxTTT:{title}</title><h1><a href="{line(0)}">{title}</a></h1>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{'' if field[1] != '-' else f'<a href="{line(1)}">'}{field[1].replace('-', '□')}{'' if field[1] != '-' else '</a>'}</td>
|
<td>{'' if field[1] != '-' else f'<a href="{line(1)}">'}{field[1].replace('-', '□')}{'' if field[1] != '-' else '</a>'}</td>
|
||||||
@@ -79,22 +106,18 @@ for field_tuple in iterable:
|
|||||||
<td>{'' if field[8] != '-' else f'<a href="{line(8)}">'}{field[8].replace('-', '□')}{'' if field[8] != '-' else '</a>'}</td>
|
<td>{'' if field[8] != '-' else f'<a href="{line(8)}">'}{field[8].replace('-', '□')}{'' if field[8] != '-' else '</a>'}</td>
|
||||||
<td>{'' if field[9] != '-' else f'<a href="{line(9)}">'}{field[9].replace('-', '□')}{'' if field[9] != '-' else '</a>'}</td>
|
<td>{'' if field[9] != '-' else f'<a href="{line(9)}">'}{field[9].replace('-', '□')}{'' if field[9] != '-' else '</a>'}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table><script src="s.js"></script>""")
|
</table><script src="{'s' if file_mode else 'a'}.js"></script>""")
|
||||||
files[field] = f"{'<a href="../index.html">' if win != '-' else ''}{content}{'</a>' if win != '-' else ''}"
|
pages[field] = f"{'<a href=\"../index.html\">' if win != '-' else ''}{content}{'</a>' if win != '-' else ''}"
|
||||||
|
|
||||||
os.makedirs(path, exist_ok=True)
|
os.makedirs(path, exist_ok=True)
|
||||||
for filename, content in files.items():
|
for filename, content in pages.items():
|
||||||
with open(f'{path}{filename}{".html" if file_mode else ""}', 'w+', encoding='utf-8') as f:
|
with open(f'{path}{filename}{".html" if file_mode else ""}', 'w+', encoding='utf-8') as f:
|
||||||
f.write(('<meta property="og:type" content="website">' if server_mode else '')+(content.replace('.html', '') if server_mode else content))
|
f.write(('<meta property="og:type" content="website">' if server_mode else '')+(content.replace('.html', '') if server_mode else content))
|
||||||
|
|
||||||
with open(f'{path}s.js', 'w+', encoding='utf-8') as f:
|
|
||||||
f.write(minify("""
|
for filename, content in scripts.items():
|
||||||
const style=document.createElement('style');
|
with open(f'{path}{filename}.js', 'w+', encoding='utf-8') as f:
|
||||||
style.textContent='
|
f.write(content)
|
||||||
body{margin:0;padding:20px;font-family:Arial,sans-serif;text-align:center}
|
|
||||||
h1{font-size:24px;margin-bottom:20px}a{text-decoration:none;color:#007bff}
|
with open(f'{path}s.css', 'w+', encoding='utf-8') as f:
|
||||||
h1 a{color:#007bff}table{margin:0 auto;border-collapse:collapse}
|
f.write(style)
|
||||||
td{border:1px solid #ccc;padding:10px;width:50px;height:50px;
|
|
||||||
text-align:center;font-size:18px;line-height:50px;vertical-align:middle}
|
|
||||||
td a{display:block;width:100%;height:100%;line-height:50px;color:#007bff}
|
|
||||||
td:hover{background:#f0f0f0}';document.head.appendChild(style);"""))
|
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -5,6 +5,7 @@ go 1.25.3
|
|||||||
require (
|
require (
|
||||||
github.com/gin-contrib/gzip v1.2.5
|
github.com/gin-contrib/gzip v1.2.5
|
||||||
github.com/gin-gonic/gin v1.11.0
|
github.com/gin-gonic/gin v1.11.0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -32,6 +32,8 @@ github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
|
|||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
|
|||||||
@@ -4,35 +4,64 @@ import (
|
|||||||
// "flag"
|
// "flag"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-contrib/gzip"
|
"github.com/gin-contrib/gzip"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed static
|
//go:embed toe
|
||||||
var staticFiles embed.FS
|
var staticFiles embed.FS
|
||||||
|
|
||||||
func SetCustomContentType() gin.HandlerFunc {
|
func SetCustomContentType() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
requestPath := c.Request.URL.Path
|
requestPath := c.Request.URL.Path
|
||||||
if strings.HasPrefix(requestPath, "/l/static") {
|
if strings.Contains(requestPath, ".") {
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000, immutable")
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(requestPath, "/tic/tac/toe") && !strings.Contains(requestPath, ".") {
|
||||||
c.Header("Content-Type", "text/html; charset=UTF-8")
|
c.Header("Content-Type", "text/html; charset=UTF-8")
|
||||||
|
} else if strings.HasSuffix(requestPath, ".ico") {
|
||||||
|
c.Header("Content-Type", "image/svg+xml")
|
||||||
|
} else if strings.HasSuffix(requestPath, ".js") {
|
||||||
|
c.Header("Content-Type", "application/javascript")
|
||||||
|
} else if strings.HasSuffix(requestPath, ".css") {
|
||||||
|
c.Header("Content-Type", "text/css")
|
||||||
}
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var favicon = "<svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M10 10h12v12H10z\"/><path d=\"M22 22a8 8 0 0 0-12-12\" fill=\"none\" stroke=\"#f30\" stroke-width=\"2\"/><path stroke=\"#07f\" stroke-width=\"2\" d=\"m8 8 16 16M8 24l8-8\"/><path stroke=\"#000\" d=\"m8.5 7.5 16 16\"/></svg>"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
embeddedFilesSystem := http.FS(staticFiles)
|
embeddedFilesSystem := http.FS(staticFiles)
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
router.Use(SetCustomContentType())
|
router.Use(SetCustomContentType())
|
||||||
router.Use(gzip.Gzip(gzip.DefaultCompression))
|
router.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||||
router.GET("/ping", func(c *gin.Context) {
|
router.GET("/", func(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{"message": "pong"})
|
c.Redirect(http.StatusMovedPermanently, "/tic/tac/toe/index")
|
||||||
})
|
})
|
||||||
router.StaticFS("/l", embeddedFilesSystem)
|
router.GET("/favicon.ico", func(c *gin.Context) {
|
||||||
|
c.String(http.StatusOK, favicon)
|
||||||
|
})
|
||||||
|
router.GET("/multiplayer", multiplayer)
|
||||||
|
router.StaticFS("/tic/tac", embeddedFilesSystem)
|
||||||
router.Run(":8080")
|
router.Run(":8080")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func multiplayer(c *gin.Context) {
|
||||||
|
if c.GetHeader("Accept") == "*/*" {
|
||||||
|
c.String(http.StatusTeapot, "Preload not allowed")
|
||||||
|
}
|
||||||
|
u, err := uuid.NewV7()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Ошибка:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, fmt.Sprintf("ToDo\nUUID7: %s", u.String()))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user