From a4a2273a2aa27f8bde94f080b623d2a5025503eb Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Mon, 16 Dec 2024 05:36:06 -0600 Subject: [PATCH] Change config to match other config patterns and future setup for all round configs --- backend/cmd/backend/backend.go | 8 +- backend/cmd/consumer/consumer.go | 8 +- backend/cmd/video-gen/video.go | 8 +- backend/config/rounds.go | 47 ++++ backend/core/backend.go | 4 +- backend/routes/competition.go | 52 ----- backend/routes/rounds.go | 31 +++ backend/routes/routes.go | 1 + configs/competition.config.json | 7 - configs/rounds.config.json | 9 + .../src/tabs/worlds/WorldsCreationPanel.css | 4 +- .../src/tabs/worlds/WorldsCreationPanel.js | 204 ++++++++++-------- 12 files changed, 224 insertions(+), 159 deletions(-) create mode 100644 backend/config/rounds.go delete mode 100644 backend/routes/competition.go create mode 100644 backend/routes/rounds.go delete mode 100644 configs/competition.config.json create mode 100644 configs/rounds.config.json diff --git a/backend/cmd/backend/backend.go b/backend/cmd/backend/backend.go index 1821d2ee..91815afe 100644 --- a/backend/cmd/backend/backend.go +++ b/backend/cmd/backend/backend.go @@ -19,6 +19,7 @@ func isFlagSet(name string) bool { } func main() { + roundsConfigFilename := flag.String("rounds-config", config.DefaultRoundsConfigPath, "Rounds config file") canvasConfigFilename := flag.String("canvas-config", config.DefaultCanvasConfigPath, "Canvas config file") databaseConfigFilename := flag.String("database-config", config.DefaultDatabaseConfigPath, "Database config file") backendConfigFilename := flag.String("backend-config", config.DefaultBackendConfigPath, "Backend config file") @@ -27,6 +28,11 @@ func main() { flag.Parse() + roundsConfig, err := config.LoadRoundsConfig(*roundsConfigFilename) + if err != nil { + panic(err) + } + canvasConfig, err := config.LoadCanvasConfig(*canvasConfigFilename) if err != nil { panic(err) @@ -49,7 +55,7 @@ func main() { databases := core.NewDatabases(databaseConfig) defer databases.Close() - core.ArtPeaceBackend = core.NewBackend(databases, canvasConfig, backendConfig, *admin) + core.ArtPeaceBackend = core.NewBackend(databases, roundsConfig, canvasConfig, backendConfig, *admin) routes.InitRoutes() diff --git a/backend/cmd/consumer/consumer.go b/backend/cmd/consumer/consumer.go index ae8dffe6..5f87e2eb 100644 --- a/backend/cmd/consumer/consumer.go +++ b/backend/cmd/consumer/consumer.go @@ -20,6 +20,7 @@ func isFlagSet(name string) bool { } func main() { + roundsConfigFilename := flag.String("rounds-config", config.DefaultRoundsConfigPath, "Rounds config file") canvasConfigFilename := flag.String("canvas-config", config.DefaultCanvasConfigPath, "Canvas config file") databaseConfigFilename := flag.String("database-config", config.DefaultDatabaseConfigPath, "Database config file") backendConfigFilename := flag.String("backend-config", config.DefaultBackendConfigPath, "Backend config file") @@ -27,6 +28,11 @@ func main() { flag.Parse() + roundsConfig, err := config.LoadRoundsConfig(*roundsConfigFilename) + if err != nil { + panic(err) + } + canvasConfig, err := config.LoadCanvasConfig(*canvasConfigFilename) if err != nil { panic(err) @@ -49,7 +55,7 @@ func main() { databases := core.NewDatabases(databaseConfig) defer databases.Close() - core.ArtPeaceBackend = core.NewBackend(databases, canvasConfig, backendConfig, false) + core.ArtPeaceBackend = core.NewBackend(databases, roundsConfig, canvasConfig, backendConfig, false) routes.InitBaseRoutes() indexer.InitIndexerRoutes() diff --git a/backend/cmd/video-gen/video.go b/backend/cmd/video-gen/video.go index 6620761d..aec5698e 100644 --- a/backend/cmd/video-gen/video.go +++ b/backend/cmd/video-gen/video.go @@ -10,12 +10,18 @@ import ( ) func main() { + roundsConfigFilename := flag.String("rounds-config", config.DefaultRoundsConfigPath, "Rounds config file") canvasConfigFilename := flag.String("canvas-config", config.DefaultCanvasConfigPath, "Canvas config file") databaseConfigFilename := flag.String("database-config", config.DefaultDatabaseConfigPath, "Database config file") backendConfigFilename := flag.String("backend-config", config.DefaultBackendConfigPath, "Backend config file") flag.Parse() + roundsConfig, err := config.LoadRoundsConfig(*roundsConfigFilename) + if err != nil { + panic(err) + } + canvasConfig, err := config.LoadCanvasConfig(*canvasConfigFilename) if err != nil { panic(err) @@ -34,7 +40,7 @@ func main() { databases := core.NewDatabases(databaseConfig) defer databases.Close() - core.ArtPeaceBackend = core.NewBackend(databases, canvasConfig, backendConfig, true) + core.ArtPeaceBackend = core.NewBackend(databases, roundsConfig, canvasConfig, backendConfig, true) routes.InitBaseRoutes() routes.InitCanvasRoutes() diff --git a/backend/config/rounds.go b/backend/config/rounds.go new file mode 100644 index 00000000..b5198d1c --- /dev/null +++ b/backend/config/rounds.go @@ -0,0 +1,47 @@ +package config + +import ( + "encoding/json" + "os" +) + +type Round3 struct { + Width uint `json:"width"` + Height uint `json:"height"` + Timer uint `json:"timer"` + StartTime string `json:"startTime"` + EndTime string `json:"endTime"` +} + +type RoundsConfig struct { + Round3 Round3 `json:"round3"` +} + +var DefaultRoundsConfig = &RoundsConfig{ + Round3: Round3{ + Width: 256, + Height: 192, + Timer: 5, + StartTime: "2024-12-01T00:00:00Z", + EndTime: "2025-01-01T00:00:00Z", + }, +} + +var DefaultRoundsConfigPath = "../configs/rounds.config.json" + +func LoadRoundsConfig(roundsConfigPath string) (*RoundsConfig, error) { + roundsConfig := &RoundsConfig{} + + roundsConfigFile, err := os.Open(roundsConfigPath) + if err != nil { + return nil, err + } + defer roundsConfigFile.Close() + + jsonParser := json.NewDecoder(roundsConfigFile) + if err = jsonParser.Decode(roundsConfig); err != nil { + return nil, err + } + + return roundsConfig, nil +} diff --git a/backend/core/backend.go b/backend/core/backend.go index 62c460db..b580ab41 100644 --- a/backend/core/backend.go +++ b/backend/core/backend.go @@ -15,6 +15,7 @@ type Backend struct { WSConnections []*websocket.Conn WSConnectionsLock sync.Mutex + RoundsConfig *config.RoundsConfig CanvasConfig *config.CanvasConfig BackendConfig *config.BackendConfig @@ -23,9 +24,10 @@ type Backend struct { var ArtPeaceBackend *Backend -func NewBackend(databases *Databases, canvasConfig *config.CanvasConfig, backendConfig *config.BackendConfig, adminMode bool) *Backend { +func NewBackend(databases *Databases, roundsConfig *config.RoundsConfig, canvasConfig *config.CanvasConfig, backendConfig *config.BackendConfig, adminMode bool) *Backend { return &Backend{ Databases: databases, + RoundsConfig: roundsConfig, CanvasConfig: canvasConfig, BackendConfig: backendConfig, AdminMode: adminMode, diff --git a/backend/routes/competition.go b/backend/routes/competition.go deleted file mode 100644 index 5646fd7b..00000000 --- a/backend/routes/competition.go +++ /dev/null @@ -1,52 +0,0 @@ -package routes - -import ( - "encoding/json" - "net/http" - "os" - "path/filepath" - - routeutils "github.com/keep-starknet-strange/art-peace/backend/routes/utils" -) - -type CompetitionConfig struct { - Round3 struct { - Timer int `json:"timer"` - StartTime string `json:"startTime"` - EndTime string `json:"endTime"` - } `json:"round3"` -} - -func InitCompetitionRoutes() { - http.HandleFunc("/get-competition-config", getCompetitionConfig) -} - -func getCompetitionConfig(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - routeutils.WriteErrorJson(w, http.StatusMethodNotAllowed, "Method not allowed") - return - } - - // Read config file - configPath := filepath.Join("configs", "competition.config.json") - configFile, err := os.ReadFile(configPath) - if err != nil { - routeutils.WriteErrorJson(w, http.StatusInternalServerError, "Failed to read competition config") - return - } - - var config CompetitionConfig - if err := json.Unmarshal(configFile, &config); err != nil { - routeutils.WriteErrorJson(w, http.StatusInternalServerError, "Failed to parse competition config") - return - } - - // Convert to JSON and send response - jsonResponse, err := json.Marshal(config) - if err != nil { - routeutils.WriteErrorJson(w, http.StatusInternalServerError, "Failed to create response") - return - } - - routeutils.WriteDataJson(w, string(jsonResponse)) -} diff --git a/backend/routes/rounds.go b/backend/routes/rounds.go new file mode 100644 index 00000000..53a907b1 --- /dev/null +++ b/backend/routes/rounds.go @@ -0,0 +1,31 @@ +package routes + +import ( + "encoding/json" + "net/http" + + "github.com/keep-starknet-strange/art-peace/backend/core" + routeutils "github.com/keep-starknet-strange/art-peace/backend/routes/utils" +) + +func InitRoundsRoutes() { + http.HandleFunc("/get-rounds-config", getRoundsConfig) +} + +func getRoundsConfig(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + routeutils.WriteErrorJson(w, http.StatusMethodNotAllowed, "Method not allowed") + return + } + + config := core.ArtPeaceBackend.RoundsConfig + + // Marshal the config to JSON + configJson, err := json.Marshal(config) + if err != nil { + routeutils.WriteErrorJson(w, http.StatusInternalServerError, "Error marshalling config to JSON") + return + } + + routeutils.WriteDataJson(w, string(configJson)) +} diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 18aaefb7..ef6c3f6f 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go @@ -28,4 +28,5 @@ func InitRoutes() { InitWorldsRoutes() InitStencilsRoutes() InitStencilsStaticRoutes() + InitRoundsRoutes() } diff --git a/configs/competition.config.json b/configs/competition.config.json deleted file mode 100644 index 6640afdb..00000000 --- a/configs/competition.config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "round3": { - "timer": 5, - "startTime": "2023-12-06T00:00:00Z", - "endTime": "2024-01-01T00:00:00Z" - } -} \ No newline at end of file diff --git a/configs/rounds.config.json b/configs/rounds.config.json new file mode 100644 index 00000000..94f382ba --- /dev/null +++ b/configs/rounds.config.json @@ -0,0 +1,9 @@ +{ + "round3": { + "width": 256, + "height": 192, + "timer": 5, + "startTime": "2024-12-06T00:00:00Z", + "endTime": "2025-01-01T00:00:00Z" + } +} diff --git a/frontend/src/tabs/worlds/WorldsCreationPanel.css b/frontend/src/tabs/worlds/WorldsCreationPanel.css index bbad5d20..a5b059c9 100644 --- a/frontend/src/tabs/worlds/WorldsCreationPanel.css +++ b/frontend/src/tabs/worlds/WorldsCreationPanel.css @@ -1,6 +1,6 @@ .WorldsCreationPanel { position: relative; - width: 530px; + width: 100%; padding: 1rem 0.5rem 0.5rem 0.5rem; margin-bottom: 0.3rem; @@ -18,8 +18,6 @@ box-shadow: 0 0 1rem 0.1rem rgba(0, 0, 0, 0.3); border: 0.2rem solid rgba(0, 0, 0, 0.4); - right: 100px; - pointer-events: fill; } diff --git a/frontend/src/tabs/worlds/WorldsCreationPanel.js b/frontend/src/tabs/worlds/WorldsCreationPanel.js index 04f1817b..eb0aace4 100644 --- a/frontend/src/tabs/worlds/WorldsCreationPanel.js +++ b/frontend/src/tabs/worlds/WorldsCreationPanel.js @@ -194,6 +194,10 @@ const WorldsCreationPanel = (props) => { if (!checkInputs()) return; + const submitWidth = isCompetitionWorld ? getCompetitionWidth() : worldWidth; + const submitHeight = isCompetitionWorld + ? getCompetitionHeight() + : worldHeight; const submitTimer = isCompetitionWorld ? getCompetitionTimer() : timer; const submitStart = isCompetitionWorld ? getCompetitionStart() : start; const submitEnd = isCompetitionWorld ? getCompetitionEnd() : end; @@ -202,8 +206,8 @@ const WorldsCreationPanel = (props) => { await createWorldCall( worldName, worldSlug, - worldWidth, - worldHeight, + submitWidth, + submitHeight, submitTimer, palette, submitStart, @@ -220,12 +224,12 @@ const WorldsCreationPanel = (props) => { host: host, name: toHex(worldName), unique_name: toHex(worldSlug), - width: worldWidth.toString(), - height: worldHeight.toString(), - time_between_pixels: timer.toString(), + width: submitWidth.toString(), + height: submitHeight.toString(), + time_between_pixels: submitTimer.toString(), color_palette: palette.toString(), - start_time: Math.floor(start / 1000).toString(), - end_time: Math.floor(end / 1000).toString() + start_time: Math.floor(submitStart / 1000).toString(), + end_time: Math.floor(submitEnd / 1000).toString() }) }); if (response.result) { @@ -256,41 +260,46 @@ const WorldsCreationPanel = (props) => { }, [worldName]); const [competitionConfig, setCompetitionConfig] = useState(null); - const [isLoadingConfig, setIsLoadingConfig] = useState(true); // Fetch competition config when component mounts useEffect(() => { - const fetchCompetitionConfig = async () => { + const fetchRoundsConfig = async () => { try { - const response = await fetchWrapper('get-competition-config'); + const response = await fetchWrapper('get-rounds-config'); if (response.data) { setCompetitionConfig(response.data.round3); } } catch (error) { console.error('Failed to fetch competition config:', error); - } finally { - setIsLoadingConfig(false); } }; - fetchCompetitionConfig(); + fetchRoundsConfig(); }, []); + const getCompetitionWidth = () => { + return competitionConfig?.width || 128; // Fallback to default + }; + + const getCompetitionHeight = () => { + return competitionConfig?.height || 128; // Fallback to default + }; + // Use competition values from config when available const getCompetitionTimer = () => { - return competitionConfig?.timer || 5; // Fallback to default + return competitionConfig?.timer || 7; // Fallback to default }; const getCompetitionStart = () => { return competitionConfig?.startTime ? new Date(competitionConfig.startTime).getTime() - : new Date('2023-12-06').getTime(); // Fallback + : new Date('2024-12-07T00:00:00Z').getTime(); }; const getCompetitionEnd = () => { return competitionConfig?.endTime ? new Date(competitionConfig.endTime).getTime() - : new Date('2024-01-01').getTime(); // Fallback + : new Date('2025-01-02T00:00:00Z').getTime(); }; return ( @@ -321,77 +330,93 @@ const WorldsCreationPanel = (props) => { {nameError &&

{nameError}

} -
-

Size

-
-
+ {isCompetitionWorld ? ( +
+

Size

+

+ {getCompetitionWidth()} x {getCompetitionHeight()} +

+
+ ) : ( +
+

Size

+
- { - if (e.target.value < minWorldSize) { - setWorldWidth(minWorldSize); - } else if (e.target.value > maxWorldSize) { - setWorldWidth(maxWorldSize); - } else { - setWorldWidth(e.target.value); - } +
-

- Width -

-
-

 x 

-
- { - if (e.target.value < minWorldSize) { - setWorldHeight(minWorldSize); - } else if (e.target.value > maxWorldSize) { - setWorldHeight(maxWorldSize); - } else { - setWorldHeight(e.target.value); - } + > + { + if (e.target.value < minWorldSize) { + setWorldWidth(minWorldSize); + } else if (e.target.value > maxWorldSize) { + setWorldWidth(maxWorldSize); + } else { + setWorldWidth(e.target.value); + } + }} + /> +

+ Width +

+
+

 x 

+
-

- Height -

+ > + { + if (e.target.value < minWorldSize) { + setWorldHeight(minWorldSize); + } else if (e.target.value > maxWorldSize) { + setWorldHeight(maxWorldSize); + } else { + setWorldHeight(e.target.value); + } + }} + /> +

+ Height +

+
-
+ )}
- {isCompetitionWorld && ( + {isCompetitionWorld ? ( + <> +

Timer

+

+ {getCompetitionTimer()} seconds between pixels +

+ + ) : ( <>

Timer

{
- {isCompetitionWorld && ( -

- {isLoadingConfig - ? 'Loading...' - : `${getCompetitionTimer()} seconds between pixels`} -

- )}
{isCompetitionWorld ? ( -

- Start -{' '} - {isLoadingConfig - ? ' Loading...' - : new Date(getCompetitionStart()).toLocaleDateString()} -

+ <> +

Start

+

+ {new Date(getCompetitionStart()).toLocaleDateString()} +

+ ) : ( <>

Start

@@ -531,12 +549,12 @@ const WorldsCreationPanel = (props) => {
{isCompetitionWorld ? ( -
- End -{' '} - {isLoadingConfig - ? 'Loading...' - : new Date(getCompetitionEnd()).toLocaleDateString()} -
+ <> +

End

+

+ {new Date(getCompetitionEnd()).toLocaleDateString()} +

+ ) : ( <>

End