Compare commits
18 Commits
b173f6d5c4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| af7ad13ca4 | |||
| 3b6d82077f | |||
| 6f4c5a3aa7 | |||
| 544fac2a76 | |||
| 813493ffa7 | |||
| 235faddaa8 | |||
| bed126bd85 | |||
| 26f5760987 | |||
| 0c987d39b3 | |||
| ae63de364f | |||
| 2f5dd75460 | |||
| 7f88fc6b0f | |||
| b8b6d86393 | |||
| ae20c57ecb | |||
| f23a0c2152 | |||
| f1c69c0f1f | |||
| 8c2dd57e08 | |||
| a107faa366 |
@@ -5,11 +5,13 @@
|
||||
"вопрос",
|
||||
"второй",
|
||||
"дает",
|
||||
"Дело",
|
||||
"Детективы",
|
||||
"диалога",
|
||||
"диалогом",
|
||||
"другой",
|
||||
"задать",
|
||||
"запущен",
|
||||
"корректный",
|
||||
"Можно",
|
||||
"Название",
|
||||
@@ -27,6 +29,7 @@
|
||||
"приложением",
|
||||
"проходами",
|
||||
"проходом",
|
||||
"сервер",
|
||||
"скрытой",
|
||||
"скрытую",
|
||||
"существует",
|
||||
@@ -38,10 +41,12 @@
|
||||
"точку",
|
||||
"читайте",
|
||||
"AUTOINCREMENT",
|
||||
"GOARCH",
|
||||
"gopdf",
|
||||
"gwmux",
|
||||
"localtime",
|
||||
"palces",
|
||||
"protoc",
|
||||
"qrcode",
|
||||
"signintech",
|
||||
"stretchr"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM alpine:latest
|
||||
RUN apk add --no-cache ca-certificates
|
||||
COPY bin/evening_detective /usr/local/bin/evening_detective
|
||||
COPY evening_detective_linux_arm64 /usr/local/bin/evening_detective
|
||||
RUN chmod +x /usr/local/bin/evening_detective
|
||||
CMD ["/usr/local/bin/evening_detective"]
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
FROM golang:1.26-alpine
|
||||
RUN apk add --no-cache gcc musl-dev
|
||||
@@ -12,10 +12,24 @@ generate:
|
||||
run:
|
||||
go run ./cmd/evening_detective/main.go
|
||||
|
||||
build:
|
||||
build-builder:
|
||||
docker build -f Dockerfile.builder -t my-go-builder .
|
||||
|
||||
build-macos:
|
||||
rm -rf bin
|
||||
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o bin/evening_detective_macos_arm64 cmd/evening_detective/main.go
|
||||
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o bin/evening_detective_macos_amd64 cmd/evening_detective/main.go
|
||||
cp bin/evening_detective_macos_arm64 ../evening_detective_stories
|
||||
ls ../evening_detective_stories | grep Дело | xargs -I {} cp -f bin/evening_detective_macos_arm64 "../evening_detective_stories/{}/game/"
|
||||
|
||||
build-linux:
|
||||
docker run --rm \
|
||||
-v "$$PWD":/app \
|
||||
-w /app \
|
||||
my-go-builder sh -c \
|
||||
"CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o bin/evening_detective_linux_arm64 cmd/evening_detective/main.go"
|
||||
ls ../evening_detective_stories | grep Дело | xargs -I {} cp -f bin/evening_detective_linux_arm64 "../evening_detective_stories/{}/game/"
|
||||
ls ../evening_detective_stories | grep Дело | xargs -I {} cp -f docker-compose.yml "../evening_detective_stories/{}/game/"
|
||||
ls ../evening_detective_stories | grep Дело | xargs -I {} cp -f Dockerfile "../evening_detective_stories/{}/game/"
|
||||
|
||||
text_to_story:
|
||||
rm -f ./cmd/text_to_story/story.json
|
||||
|
||||
@@ -230,9 +230,18 @@ message GraphNode {
|
||||
string code = 1;
|
||||
string name = 2;
|
||||
string text = 3;
|
||||
repeated GraphApplication applications = 4;
|
||||
string image = 4;
|
||||
repeated GraphApplication applications = 5;
|
||||
bool hidden = 7;
|
||||
repeated GraphDoor doors = 8;
|
||||
}
|
||||
|
||||
message GraphApplication {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message GraphDoor {
|
||||
string code = 1;
|
||||
string name = 2;
|
||||
bool show = 3;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,10 @@ var userFS embed.FS
|
||||
var adminFS embed.FS
|
||||
|
||||
func main() {
|
||||
// Create a listener on TCP port
|
||||
lis, err := net.Listen("tcp", ":8080")
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to listen:", err)
|
||||
}
|
||||
grpcGatewayHost := config.GetGrpcGatewayHost()
|
||||
userClientHost := config.GetUserClientHost()
|
||||
adminClientHost := config.GetAdminClientHost()
|
||||
fileHost := config.GetFileHost()
|
||||
|
||||
// Create a gRPC server object
|
||||
s := grpc.NewServer()
|
||||
@@ -50,10 +49,6 @@ func main() {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
clientHost := config.GetHost()
|
||||
adminClientHost := config.GetAdminHost()
|
||||
fileHost := config.GetFileHost()
|
||||
|
||||
cleaner := cleaner.NewCleaner()
|
||||
|
||||
formatter := formatter.NewFormatter()
|
||||
@@ -72,7 +67,7 @@ func main() {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
linkService := link.NewLinkService(clientHost)
|
||||
linkService := link.NewLinkService(userClientHost)
|
||||
|
||||
passwordGenerator := password.NewPasswordGenerator()
|
||||
|
||||
@@ -90,12 +85,17 @@ func main() {
|
||||
),
|
||||
),
|
||||
)
|
||||
// Serve gRPC server
|
||||
log.Println("Serving gRPC on 0.0.0.0:8080")
|
||||
|
||||
// Server gRPC
|
||||
lis, err := net.Listen("tcp", ":8080")
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to listen:", err)
|
||||
}
|
||||
go func() {
|
||||
log.Fatalln(s.Serve(lis))
|
||||
}()
|
||||
|
||||
// Client gRPC
|
||||
// Create a client connection to the gRPC server we just started
|
||||
// This is where the gRPC-Gateway proxies the requests
|
||||
conn, err := grpc.NewClient(
|
||||
@@ -122,13 +122,12 @@ func main() {
|
||||
log.Fatalln("Failed to register gateway:", err)
|
||||
}
|
||||
|
||||
// Server gRPC-Gateway
|
||||
gwServer := &http.Server{
|
||||
Addr: ":8090",
|
||||
Addr: config.GrpcGatewayPort,
|
||||
Handler: cors(gwmux),
|
||||
}
|
||||
|
||||
// Serve gRPC-Gateway server
|
||||
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
|
||||
log.Printf("Serving %s for gRPC-Gateway\n", grpcGatewayHost)
|
||||
go func() {
|
||||
log.Fatalln(gwServer.ListenAndServe())
|
||||
}()
|
||||
@@ -141,23 +140,18 @@ func main() {
|
||||
fileServerUser := http.FileServer(http.FS(subUserFS))
|
||||
muxUser.Handle("/", fileServerUser)
|
||||
|
||||
// Serve user web server
|
||||
log.Println("Serving user web on http://0.0.0.0" + config.ClientPort)
|
||||
// Server user web
|
||||
log.Printf("Serving %s for user web\n", userClientHost)
|
||||
go func() {
|
||||
log.Fatalln(http.ListenAndServe(config.ClientPort, muxUser))
|
||||
log.Fatalln(http.ListenAndServe(config.UserClientPort, muxUser))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
dir := "./data/story/images"
|
||||
// Создаем файловый сервер
|
||||
fs := http.FileServer(http.Dir(dir))
|
||||
|
||||
// Добавляем middleware для логирования
|
||||
http.Handle("/", loggingMiddleware(fs))
|
||||
|
||||
log.Println("Файловый сервер запущен на http://localhost:8120")
|
||||
log.Println("Обслуживается директория: " + dir)
|
||||
log.Fatal(http.ListenAndServe(":8120", nil))
|
||||
log.Printf("Serving %s for file server, directory: %s\n", fileHost, dir)
|
||||
log.Fatal(http.ListenAndServe(config.FilePort, nil))
|
||||
}()
|
||||
|
||||
muxAdmin := http.NewServeMux()
|
||||
@@ -168,9 +162,13 @@ func main() {
|
||||
fileServerAdmin := http.FileServer(http.FS(subAdminFS))
|
||||
muxAdmin.Handle("/", fileServerAdmin)
|
||||
|
||||
// Serve admin web server
|
||||
log.Printf("Serving admin web on %s\n", adminClientHost)
|
||||
log.Fatalln(http.ListenAndServe(":8110", muxAdmin))
|
||||
// Server admin web
|
||||
adminWebServer := &http.Server{
|
||||
Addr: config.AdminClientPort,
|
||||
Handler: muxAdmin,
|
||||
}
|
||||
log.Printf("Serving %s for admin web \n", adminClientHost)
|
||||
log.Fatalln(adminWebServer.ListenAndServe())
|
||||
}
|
||||
|
||||
func cors(h http.Handler) http.Handler {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ВД Админка</title>
|
||||
<script type="module" crossorigin src="/assets/index-CH9kKe_e.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C16dKKOO.css">
|
||||
<script type="module" crossorigin src="/assets/index-c8po_p3Q.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CgpxTv-m.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
|
Before Width: | Height: | Size: 442 KiB |
|
After Width: | Height: | Size: 442 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 802 KiB |
|
Before Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 310 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 326 KiB |
|
Before Width: | Height: | Size: 859 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 603 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 195 KiB |
@@ -5,8 +5,8 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Вечерний детектив</title>
|
||||
<script type="module" crossorigin src="/assets/index-CBvKsrC1.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BkPf0Nib.css">
|
||||
<script type="module" crossorigin src="/assets/index-CQcj9qbi.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C2dfznw-.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -6,14 +6,47 @@ services:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8090:8090"
|
||||
- "8100:8100"
|
||||
- "8110:8110"
|
||||
- "8090:8090" # api
|
||||
- "8100:8100" # user
|
||||
- "8110:8110" # admin
|
||||
- "8120:8120" # files
|
||||
environment:
|
||||
- HOST=https://evening-detective.crabs-games.art
|
||||
- FILE_HOST=https://evening-detective-files.crabs-games.art
|
||||
networks:
|
||||
- crabs-network
|
||||
volumes:
|
||||
- data:/data
|
||||
# environment:
|
||||
# - ENV_VAR_NAME=env_var_value
|
||||
- ./data:/data
|
||||
labels:
|
||||
# api
|
||||
reproxy.1.server: "evening-detective-api.crabs-games.art"
|
||||
reproxy.1.route: "/(.*)"
|
||||
reproxy.1.dest: "http://evening_detective:8090/$$1"
|
||||
reproxy.1.port: "8090"
|
||||
reproxy.1.ping: "/"
|
||||
|
||||
volumes:
|
||||
data:
|
||||
# user
|
||||
reproxy.2.server: "evening-detective.crabs-games.art"
|
||||
reproxy.2.route: "/(.*)"
|
||||
reproxy.2.dest: "http://evening_detective:8100/$$1"
|
||||
reproxy.2.port: "8100"
|
||||
reproxy.2.ping: "/"
|
||||
|
||||
# admin
|
||||
reproxy.3.server: "evening-detective-admin.crabs-games.art"
|
||||
reproxy.3.route: "/(.*)"
|
||||
reproxy.3.dest: "http://evening_detective:8110/$$1"
|
||||
reproxy.3.port: "8110"
|
||||
reproxy.3.ping: "/"
|
||||
|
||||
# files
|
||||
reproxy.4.server: "evening-detective-files.crabs-games.art"
|
||||
reproxy.4.route: "/(.*)"
|
||||
reproxy.4.dest: "http://evening_detective:8120/$$1"
|
||||
reproxy.4.port: "8120"
|
||||
reproxy.4.ping: "/"
|
||||
|
||||
networks:
|
||||
crabs-network:
|
||||
name: crabs-network
|
||||
external: true
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
module evening_detective
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.5
|
||||
go 1.26
|
||||
|
||||
require (
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2
|
||||
google.golang.org/grpc v1.75.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/golang/glog v1.2.5 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.3 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -37,9 +29,7 @@ require (
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
google.golang.org/protobuf v1.36.7
|
||||
)
|
||||
|
||||
tool github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ClientPort = ":8100"
|
||||
GrpcGatewayPort = ":8090"
|
||||
UserClientPort = ":8100"
|
||||
AdminClientPort = ":8110"
|
||||
FilePort = ":8120"
|
||||
)
|
||||
@@ -20,7 +21,19 @@ func GetDBFilepath() string {
|
||||
return getFilepath("DB_FILENAME", "data/db/store.db")
|
||||
}
|
||||
|
||||
func GetAdminHost() string {
|
||||
func GetGrpcGatewayHost() string {
|
||||
host := os.Getenv("HOST")
|
||||
if host != "" {
|
||||
return host
|
||||
}
|
||||
ips, err := getLocalIPs()
|
||||
if err != nil || len(ips) == 0 {
|
||||
return "http://127.0.0.1" + GrpcGatewayPort
|
||||
}
|
||||
return "http://" + ips[0] + GrpcGatewayPort
|
||||
}
|
||||
|
||||
func GetAdminClientHost() string {
|
||||
host := os.Getenv("HOST")
|
||||
if host != "" {
|
||||
return host
|
||||
@@ -32,16 +45,16 @@ func GetAdminHost() string {
|
||||
return "http://" + ips[0] + AdminClientPort
|
||||
}
|
||||
|
||||
func GetHost() string {
|
||||
func GetUserClientHost() string {
|
||||
host := os.Getenv("HOST")
|
||||
if host != "" {
|
||||
return host
|
||||
}
|
||||
ips, err := getLocalIPs()
|
||||
if err != nil || len(ips) == 0 {
|
||||
return "http://127.0.0.1" + ClientPort
|
||||
return "http://127.0.0.1" + UserClientPort
|
||||
}
|
||||
return "http://" + ips[0] + ClientPort
|
||||
return "http://" + ips[0] + UserClientPort
|
||||
}
|
||||
|
||||
func GetFileHost() string {
|
||||
|
||||
@@ -2,4 +2,5 @@ package formatter
|
||||
|
||||
type IFormatter interface {
|
||||
FormatText(text string) string
|
||||
FormatString(text string) string
|
||||
}
|
||||
|
||||
@@ -40,3 +40,11 @@ func (s *service) FormatText(text string) string {
|
||||
}
|
||||
return res.String()
|
||||
}
|
||||
|
||||
func (s *service) FormatString(text string) string {
|
||||
l := strings.TrimSpace(text)
|
||||
if strings.HasPrefix(l, "--") {
|
||||
l = strings.Replace(l, "--", "—", 1)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func NewDBService(filepath string) (IDBService, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("load db from: %s", filepath)
|
||||
log.Printf("Load db from: %s", filepath)
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL CHECK(length(trim(name)) > 0), password TEXT);")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -232,11 +232,25 @@ func (s *Services) UpdateNode(ctx context.Context, req *proto.UpdateNodeReq) (*p
|
||||
},
|
||||
)
|
||||
}
|
||||
doors := make([]*story_service.GraphDoor, 0, len(req.Node.Doors))
|
||||
for _, door := range req.Node.Doors {
|
||||
doors = append(
|
||||
doors,
|
||||
&story_service.GraphDoor{
|
||||
Code: door.Code,
|
||||
Name: door.Name,
|
||||
Show: door.Show,
|
||||
},
|
||||
)
|
||||
}
|
||||
node := &story_service.GraphNode{
|
||||
Code: req.Node.Code,
|
||||
Name: req.Node.Name,
|
||||
Text: req.Node.Text,
|
||||
Image: req.Node.Image,
|
||||
Applications: applications,
|
||||
Hidden: req.Node.Hidden,
|
||||
Doors: doors,
|
||||
}
|
||||
if err := s.storyService.UpdatePlace(ctx, req.Code, node); err != nil {
|
||||
return nil, err
|
||||
@@ -257,11 +271,25 @@ func (s *Services) GetGraph(ctx context.Context, req *proto.GetGraphReq) (*proto
|
||||
},
|
||||
)
|
||||
}
|
||||
doors := make([]*proto.GraphDoor, 0, len(node.Doors))
|
||||
for _, door := range node.Doors {
|
||||
doors = append(
|
||||
doors,
|
||||
&proto.GraphDoor{
|
||||
Code: door.Code,
|
||||
Name: door.Name,
|
||||
Show: door.Show,
|
||||
},
|
||||
)
|
||||
}
|
||||
nodes = append(nodes, &proto.GraphNode{
|
||||
Code: node.Code,
|
||||
Name: node.Name,
|
||||
Text: node.Text,
|
||||
Image: node.Image,
|
||||
Applications: applications,
|
||||
Hidden: node.Hidden,
|
||||
Doors: doors,
|
||||
})
|
||||
}
|
||||
edges := make([]*proto.GetGraphRsp_Edge, 0, len(graph.Edges))
|
||||
|
||||
@@ -9,7 +9,10 @@ type GraphNode struct {
|
||||
Code string
|
||||
Name string
|
||||
Text string
|
||||
Image string
|
||||
Applications []*GraphApplication
|
||||
Hidden bool
|
||||
Doors []*GraphDoor
|
||||
}
|
||||
|
||||
type GraphEdge struct {
|
||||
@@ -21,3 +24,9 @@ type GraphEdge struct {
|
||||
type GraphApplication struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
type GraphDoor struct {
|
||||
Code string
|
||||
Name string
|
||||
Show bool
|
||||
}
|
||||
|
||||
@@ -175,9 +175,12 @@ func (s *StoryService) updatePlace(ctx context.Context, code string, node *Graph
|
||||
if s.story.Places[i].Code == code {
|
||||
s.story.Places[i] = models.NewPlace(
|
||||
node.Code,
|
||||
node.Name,
|
||||
s.formatter.FormatString(node.Name),
|
||||
s.formatter.FormatText(node.Text),
|
||||
models.WithPlaceImage(node.Image),
|
||||
models.WithPlaceApplication(s.getApplications(node)...),
|
||||
models.WithPlaceHidden(node.Hidden),
|
||||
models.WithPlaceDoors(s.getDoors(node)...),
|
||||
)
|
||||
return s.Update(ctx)
|
||||
}
|
||||
@@ -186,9 +189,12 @@ func (s *StoryService) updatePlace(ctx context.Context, code string, node *Graph
|
||||
if s.story.Places[i].Code == node.Code {
|
||||
s.story.Places[i] = models.NewPlace(
|
||||
code,
|
||||
node.Name,
|
||||
s.formatter.FormatString(node.Name),
|
||||
s.formatter.FormatText(node.Text),
|
||||
models.WithPlaceImage(node.Image),
|
||||
models.WithPlaceApplication(s.getApplications(node)...),
|
||||
models.WithPlaceHidden(node.Hidden),
|
||||
models.WithPlaceDoors(s.getDoors(node)...),
|
||||
)
|
||||
break
|
||||
}
|
||||
@@ -202,13 +208,28 @@ func (s *StoryService) getApplications(node *GraphNode) []*models.Application {
|
||||
nodeApplications = append(
|
||||
nodeApplications,
|
||||
&models.Application{
|
||||
Name: application.Name,
|
||||
Name: s.formatter.FormatString(application.Name),
|
||||
},
|
||||
)
|
||||
}
|
||||
return nodeApplications
|
||||
}
|
||||
|
||||
func (s *StoryService) getDoors(node *GraphNode) []*models.Door {
|
||||
nodeDoors := make([]*models.Door, 0, len(node.Doors))
|
||||
for _, door := range node.Doors {
|
||||
nodeDoors = append(
|
||||
nodeDoors,
|
||||
&models.Door{
|
||||
Code: door.Code,
|
||||
Name: s.formatter.FormatString(door.Name),
|
||||
Show: door.Show,
|
||||
},
|
||||
)
|
||||
}
|
||||
return nodeDoors
|
||||
}
|
||||
|
||||
func (s *StoryService) GetGraph(ctx context.Context) *Graph {
|
||||
m := make(map[string]string, len(s.story.Places))
|
||||
nodes := make([]*GraphNode, 0, len(s.story.Places))
|
||||
@@ -223,12 +244,26 @@ func (s *StoryService) GetGraph(ctx context.Context) *Graph {
|
||||
},
|
||||
)
|
||||
}
|
||||
doors := make([]*GraphDoor, 0, len(place.Doors))
|
||||
for _, door := range place.Doors {
|
||||
doors = append(
|
||||
doors,
|
||||
&GraphDoor{
|
||||
Code: door.Code,
|
||||
Name: door.Name,
|
||||
Show: door.Show,
|
||||
},
|
||||
)
|
||||
}
|
||||
nodes = append(
|
||||
nodes, &GraphNode{
|
||||
Code: place.Code,
|
||||
Name: place.Name,
|
||||
Text: place.Text,
|
||||
Image: place.Image,
|
||||
Applications: applications,
|
||||
Hidden: place.Hidden,
|
||||
Doors: doors,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -259,6 +294,16 @@ func (s *StoryService) GetGraph(ctx context.Context) *Graph {
|
||||
)
|
||||
}
|
||||
}
|
||||
for _, door := range place.Doors {
|
||||
edges = append(
|
||||
edges,
|
||||
&GraphEdge{
|
||||
From: m[s.cleaner.ClearCode(place.Code)],
|
||||
To: m[s.cleaner.ClearCode(door.Code)],
|
||||
Type: "door",
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return &Graph{
|
||||
|
||||
@@ -25,11 +25,12 @@ func (s *fileService) Load(ctx context.Context) (*models.Story, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("story file %s not found", s.filepath)
|
||||
}
|
||||
log.Printf("load story from: %s", s.filepath)
|
||||
log.Printf("Load story from: %s", s.filepath)
|
||||
story := &models.Story{}
|
||||
if err := json.Unmarshal(data, story); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("Found %d places", len(story.Places))
|
||||
return story, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1539,7 +1539,10 @@ type GraphNode struct {
|
||||
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Text string `protobuf:"bytes,3,opt,name=text,proto3" json:"text,omitempty"`
|
||||
Applications []*GraphApplication `protobuf:"bytes,4,rep,name=applications,proto3" json:"applications,omitempty"`
|
||||
Image string `protobuf:"bytes,4,opt,name=image,proto3" json:"image,omitempty"`
|
||||
Applications []*GraphApplication `protobuf:"bytes,5,rep,name=applications,proto3" json:"applications,omitempty"`
|
||||
Hidden bool `protobuf:"varint,7,opt,name=hidden,proto3" json:"hidden,omitempty"`
|
||||
Doors []*GraphDoor `protobuf:"bytes,8,rep,name=doors,proto3" json:"doors,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -1595,6 +1598,13 @@ func (x *GraphNode) GetText() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GraphNode) GetImage() string {
|
||||
if x != nil {
|
||||
return x.Image
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GraphNode) GetApplications() []*GraphApplication {
|
||||
if x != nil {
|
||||
return x.Applications
|
||||
@@ -1602,6 +1612,20 @@ func (x *GraphNode) GetApplications() []*GraphApplication {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GraphNode) GetHidden() bool {
|
||||
if x != nil {
|
||||
return x.Hidden
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GraphNode) GetDoors() []*GraphDoor {
|
||||
if x != nil {
|
||||
return x.Doors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GraphApplication struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
@@ -1646,6 +1670,66 @@ func (x *GraphApplication) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type GraphDoor struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Show bool `protobuf:"varint,3,opt,name=show,proto3" json:"show,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GraphDoor) Reset() {
|
||||
*x = GraphDoor{}
|
||||
mi := &file_main_proto_msgTypes[34]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GraphDoor) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GraphDoor) ProtoMessage() {}
|
||||
|
||||
func (x *GraphDoor) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_main_proto_msgTypes[34]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GraphDoor.ProtoReflect.Descriptor instead.
|
||||
func (*GraphDoor) Descriptor() ([]byte, []int) {
|
||||
return file_main_proto_rawDescGZIP(), []int{34}
|
||||
}
|
||||
|
||||
func (x *GraphDoor) GetCode() string {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GraphDoor) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GraphDoor) GetShow() bool {
|
||||
if x != nil {
|
||||
return x.Show
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type GetGraphRsp_Edge struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
|
||||
@@ -1658,7 +1742,7 @@ type GetGraphRsp_Edge struct {
|
||||
|
||||
func (x *GetGraphRsp_Edge) Reset() {
|
||||
*x = GetGraphRsp_Edge{}
|
||||
mi := &file_main_proto_msgTypes[34]
|
||||
mi := &file_main_proto_msgTypes[35]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1670,7 +1754,7 @@ func (x *GetGraphRsp_Edge) String() string {
|
||||
func (*GetGraphRsp_Edge) ProtoMessage() {}
|
||||
|
||||
func (x *GetGraphRsp_Edge) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_main_proto_msgTypes[34]
|
||||
mi := &file_main_proto_msgTypes[35]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1809,14 +1893,21 @@ const file_main_proto_rawDesc = "" +
|
||||
"\rUpdateNodeReq\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\tR\x04code\x126\n" +
|
||||
"\x04node\x18\x02 \x01(\v2\".crabs.evening_detective.GraphNodeR\x04node\"\x0f\n" +
|
||||
"\rUpdateNodeRsp\"\x96\x01\n" +
|
||||
"\rUpdateNodeRsp\"\xfe\x01\n" +
|
||||
"\tGraphNode\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\tR\x04code\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04text\x18\x03 \x01(\tR\x04text\x12M\n" +
|
||||
"\fapplications\x18\x04 \x03(\v2).crabs.evening_detective.GraphApplicationR\fapplications\"&\n" +
|
||||
"\x04text\x18\x03 \x01(\tR\x04text\x12\x14\n" +
|
||||
"\x05image\x18\x04 \x01(\tR\x05image\x12M\n" +
|
||||
"\fapplications\x18\x05 \x03(\v2).crabs.evening_detective.GraphApplicationR\fapplications\x12\x16\n" +
|
||||
"\x06hidden\x18\a \x01(\bR\x06hidden\x128\n" +
|
||||
"\x05doors\x18\b \x03(\v2\".crabs.evening_detective.GraphDoorR\x05doors\"&\n" +
|
||||
"\x10GraphApplication\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name2\xe4\v\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\"G\n" +
|
||||
"\tGraphDoor\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\tR\x04code\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04show\x18\x03 \x01(\bR\x04show2\xe4\v\n" +
|
||||
"\x10EveningDetective\x12Y\n" +
|
||||
"\x04Ping\x12 .crabs.evening_detective.PingReq\x1a .crabs.evening_detective.PingRsp\"\r\x82\xd3\xe4\x93\x02\a\x12\x05/ping\x12i\n" +
|
||||
"\bAddTeams\x12$.crabs.evening_detective.AddTeamsReq\x1a$.crabs.evening_detective.AddTeamsRsp\"\x11\x82\xd3\xe4\x93\x02\v:\x01*\"\x06/teams\x12f\n" +
|
||||
@@ -1847,7 +1938,7 @@ func file_main_proto_rawDescGZIP() []byte {
|
||||
return file_main_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 35)
|
||||
var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 36)
|
||||
var file_main_proto_goTypes = []any{
|
||||
(*PingReq)(nil), // 0: crabs.evening_detective.PingReq
|
||||
(*PingRsp)(nil), // 1: crabs.evening_detective.PingRsp
|
||||
@@ -1883,7 +1974,8 @@ var file_main_proto_goTypes = []any{
|
||||
(*UpdateNodeRsp)(nil), // 31: crabs.evening_detective.UpdateNodeRsp
|
||||
(*GraphNode)(nil), // 32: crabs.evening_detective.GraphNode
|
||||
(*GraphApplication)(nil), // 33: crabs.evening_detective.GraphApplication
|
||||
(*GetGraphRsp_Edge)(nil), // 34: crabs.evening_detective.GetGraphRsp.Edge
|
||||
(*GraphDoor)(nil), // 34: crabs.evening_detective.GraphDoor
|
||||
(*GetGraphRsp_Edge)(nil), // 35: crabs.evening_detective.GetGraphRsp.Edge
|
||||
}
|
||||
var file_main_proto_depIdxs = []int32{
|
||||
3, // 0: crabs.evening_detective.AddTeamsReq.teams:type_name -> crabs.evening_detective.Team
|
||||
@@ -1895,40 +1987,41 @@ var file_main_proto_depIdxs = []int32{
|
||||
12, // 6: crabs.evening_detective.Action.doors:type_name -> crabs.evening_detective.Door
|
||||
11, // 7: crabs.evening_detective.GiveApplicationsReq.applications:type_name -> crabs.evening_detective.Application
|
||||
32, // 8: crabs.evening_detective.GetGraphRsp.nodes:type_name -> crabs.evening_detective.GraphNode
|
||||
34, // 9: crabs.evening_detective.GetGraphRsp.edges:type_name -> crabs.evening_detective.GetGraphRsp.Edge
|
||||
35, // 9: crabs.evening_detective.GetGraphRsp.edges:type_name -> crabs.evening_detective.GetGraphRsp.Edge
|
||||
32, // 10: crabs.evening_detective.UpdateNodeReq.node:type_name -> crabs.evening_detective.GraphNode
|
||||
33, // 11: crabs.evening_detective.GraphNode.applications:type_name -> crabs.evening_detective.GraphApplication
|
||||
0, // 12: crabs.evening_detective.EveningDetective.Ping:input_type -> crabs.evening_detective.PingReq
|
||||
2, // 13: crabs.evening_detective.EveningDetective.AddTeams:input_type -> crabs.evening_detective.AddTeamsReq
|
||||
6, // 14: crabs.evening_detective.EveningDetective.GetTeams:input_type -> crabs.evening_detective.GetTeamsReq
|
||||
8, // 15: crabs.evening_detective.EveningDetective.GetTeamsCSV:input_type -> crabs.evening_detective.GetTeamsCSVReq
|
||||
13, // 16: crabs.evening_detective.EveningDetective.GetTeam:input_type -> crabs.evening_detective.GetTeamReq
|
||||
15, // 17: crabs.evening_detective.EveningDetective.AddAction:input_type -> crabs.evening_detective.AddActionReq
|
||||
18, // 18: crabs.evening_detective.EveningDetective.GetGame:input_type -> crabs.evening_detective.GetGameReq
|
||||
20, // 19: crabs.evening_detective.EveningDetective.GameStart:input_type -> crabs.evening_detective.GameStartReq
|
||||
22, // 20: crabs.evening_detective.EveningDetective.GameStop:input_type -> crabs.evening_detective.GameStopReq
|
||||
24, // 21: crabs.evening_detective.EveningDetective.GiveApplications:input_type -> crabs.evening_detective.GiveApplicationsReq
|
||||
26, // 22: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:input_type -> crabs.evening_detective.DownloadTeamsQrCodesFileReq
|
||||
28, // 23: crabs.evening_detective.EveningDetective.GetGraph:input_type -> crabs.evening_detective.GetGraphReq
|
||||
30, // 24: crabs.evening_detective.EveningDetective.UpdateNode:input_type -> crabs.evening_detective.UpdateNodeReq
|
||||
1, // 25: crabs.evening_detective.EveningDetective.Ping:output_type -> crabs.evening_detective.PingRsp
|
||||
4, // 26: crabs.evening_detective.EveningDetective.AddTeams:output_type -> crabs.evening_detective.AddTeamsRsp
|
||||
7, // 27: crabs.evening_detective.EveningDetective.GetTeams:output_type -> crabs.evening_detective.GetTeamsRsp
|
||||
9, // 28: crabs.evening_detective.EveningDetective.GetTeamsCSV:output_type -> crabs.evening_detective.GetTeamsCSVRsp
|
||||
14, // 29: crabs.evening_detective.EveningDetective.GetTeam:output_type -> crabs.evening_detective.GetTeamRsp
|
||||
16, // 30: crabs.evening_detective.EveningDetective.AddAction:output_type -> crabs.evening_detective.AddActionRsp
|
||||
19, // 31: crabs.evening_detective.EveningDetective.GetGame:output_type -> crabs.evening_detective.GetGameRsp
|
||||
21, // 32: crabs.evening_detective.EveningDetective.GameStart:output_type -> crabs.evening_detective.GameStartRsp
|
||||
23, // 33: crabs.evening_detective.EveningDetective.GameStop:output_type -> crabs.evening_detective.GameStopRsp
|
||||
25, // 34: crabs.evening_detective.EveningDetective.GiveApplications:output_type -> crabs.evening_detective.GiveApplicationsRsp
|
||||
27, // 35: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:output_type -> crabs.evening_detective.DownloadTeamsQrCodesFileRsp
|
||||
29, // 36: crabs.evening_detective.EveningDetective.GetGraph:output_type -> crabs.evening_detective.GetGraphRsp
|
||||
31, // 37: crabs.evening_detective.EveningDetective.UpdateNode:output_type -> crabs.evening_detective.UpdateNodeRsp
|
||||
25, // [25:38] is the sub-list for method output_type
|
||||
12, // [12:25] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
34, // 12: crabs.evening_detective.GraphNode.doors:type_name -> crabs.evening_detective.GraphDoor
|
||||
0, // 13: crabs.evening_detective.EveningDetective.Ping:input_type -> crabs.evening_detective.PingReq
|
||||
2, // 14: crabs.evening_detective.EveningDetective.AddTeams:input_type -> crabs.evening_detective.AddTeamsReq
|
||||
6, // 15: crabs.evening_detective.EveningDetective.GetTeams:input_type -> crabs.evening_detective.GetTeamsReq
|
||||
8, // 16: crabs.evening_detective.EveningDetective.GetTeamsCSV:input_type -> crabs.evening_detective.GetTeamsCSVReq
|
||||
13, // 17: crabs.evening_detective.EveningDetective.GetTeam:input_type -> crabs.evening_detective.GetTeamReq
|
||||
15, // 18: crabs.evening_detective.EveningDetective.AddAction:input_type -> crabs.evening_detective.AddActionReq
|
||||
18, // 19: crabs.evening_detective.EveningDetective.GetGame:input_type -> crabs.evening_detective.GetGameReq
|
||||
20, // 20: crabs.evening_detective.EveningDetective.GameStart:input_type -> crabs.evening_detective.GameStartReq
|
||||
22, // 21: crabs.evening_detective.EveningDetective.GameStop:input_type -> crabs.evening_detective.GameStopReq
|
||||
24, // 22: crabs.evening_detective.EveningDetective.GiveApplications:input_type -> crabs.evening_detective.GiveApplicationsReq
|
||||
26, // 23: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:input_type -> crabs.evening_detective.DownloadTeamsQrCodesFileReq
|
||||
28, // 24: crabs.evening_detective.EveningDetective.GetGraph:input_type -> crabs.evening_detective.GetGraphReq
|
||||
30, // 25: crabs.evening_detective.EveningDetective.UpdateNode:input_type -> crabs.evening_detective.UpdateNodeReq
|
||||
1, // 26: crabs.evening_detective.EveningDetective.Ping:output_type -> crabs.evening_detective.PingRsp
|
||||
4, // 27: crabs.evening_detective.EveningDetective.AddTeams:output_type -> crabs.evening_detective.AddTeamsRsp
|
||||
7, // 28: crabs.evening_detective.EveningDetective.GetTeams:output_type -> crabs.evening_detective.GetTeamsRsp
|
||||
9, // 29: crabs.evening_detective.EveningDetective.GetTeamsCSV:output_type -> crabs.evening_detective.GetTeamsCSVRsp
|
||||
14, // 30: crabs.evening_detective.EveningDetective.GetTeam:output_type -> crabs.evening_detective.GetTeamRsp
|
||||
16, // 31: crabs.evening_detective.EveningDetective.AddAction:output_type -> crabs.evening_detective.AddActionRsp
|
||||
19, // 32: crabs.evening_detective.EveningDetective.GetGame:output_type -> crabs.evening_detective.GetGameRsp
|
||||
21, // 33: crabs.evening_detective.EveningDetective.GameStart:output_type -> crabs.evening_detective.GameStartRsp
|
||||
23, // 34: crabs.evening_detective.EveningDetective.GameStop:output_type -> crabs.evening_detective.GameStopRsp
|
||||
25, // 35: crabs.evening_detective.EveningDetective.GiveApplications:output_type -> crabs.evening_detective.GiveApplicationsRsp
|
||||
27, // 36: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:output_type -> crabs.evening_detective.DownloadTeamsQrCodesFileRsp
|
||||
29, // 37: crabs.evening_detective.EveningDetective.GetGraph:output_type -> crabs.evening_detective.GetGraphRsp
|
||||
31, // 38: crabs.evening_detective.EveningDetective.UpdateNode:output_type -> crabs.evening_detective.UpdateNodeRsp
|
||||
26, // [26:39] is the sub-list for method output_type
|
||||
13, // [13:26] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_main_proto_init() }
|
||||
@@ -1942,7 +2035,7 @@ func file_main_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_main_proto_rawDesc), len(file_main_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 35,
|
||||
NumMessages: 36,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -607,6 +607,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"evening_detectiveGraphDoor": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"show": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"evening_detectiveGraphNode": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -619,11 +633,23 @@
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"image": {
|
||||
"type": "string"
|
||||
},
|
||||
"applications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/evening_detectiveGraphApplication"
|
||||
}
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"doors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/evening_detectiveGraphDoor"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||