From f2b6d1174803941b954bc44d85c208b0e76f06a2 Mon Sep 17 00:00:00 2001 From: Brandon R <54774639+b-j-roberts@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:00:38 -0500 Subject: [PATCH] feat: Go formatting CI (#40) * Go formatting CI check * Main.go formatted * go format * Change go module name to github repo and patched issue in integration scripts due to new init param --- .github/workflows/build.yml | 3 + .gitignore | 2 +- backend/backend/backend.go | 33 ------ backend/backend/databases.go | 46 -------- backend/config/backend.go | 50 ++++----- backend/config/canvas.go | 62 +++++----- backend/config/database.go | 64 +++++------ backend/core/backend.go | 33 ++++++ backend/core/databases.go | 46 ++++++++ backend/go.mod | 2 +- backend/main.go | 24 ++-- backend/routes/canvas.go | 55 +++++---- backend/routes/contract.go | 26 ++--- backend/routes/indexer.go | 152 ++++++++++++------------- backend/routes/pixel.go | 146 ++++++++++++------------ backend/routes/routes.go | 14 +-- backend/routes/templates.go | 175 ++++++++++++++--------------- backend/routes/user.go | 26 ++--- backend/routes/websocket.go | 42 +++---- tests/integration/docker/deploy.sh | 4 +- tests/integration/local/deploy.sh | 2 +- 21 files changed, 504 insertions(+), 503 deletions(-) delete mode 100644 backend/backend/backend.go delete mode 100644 backend/backend/databases.go create mode 100644 backend/core/backend.go create mode 100644 backend/core/databases.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 62078d64..e13890cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,3 +18,6 @@ jobs: working-directory: onchain - run: scarb build working-directory: onchain + - name: go formatting ( gofmt -s -w . ) + run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi + working-directory: backend diff --git a/.gitignore b/.gitignore index 06696aae..540c8fcd 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ build/ node_modules/ # Backend -art-peace-backend +/backend/backend diff --git a/backend/backend/backend.go b/backend/backend/backend.go deleted file mode 100644 index 263f9423..00000000 --- a/backend/backend/backend.go +++ /dev/null @@ -1,33 +0,0 @@ -package backend - -import ( - "fmt" - "net/http" - - "github.com/gorilla/websocket" - - "art-peace-backend/config" -) - -type Backend struct { - Databases *Databases - WSConnections []*websocket.Conn - - CanvasConfig *config.CanvasConfig - BackendConfig *config.BackendConfig -} - -var ArtPeaceBackend *Backend - -func NewBackend(databases *Databases, canvasConfig *config.CanvasConfig, backendConfig *config.BackendConfig) *Backend { - return &Backend{ - Databases: databases, - CanvasConfig: canvasConfig, - BackendConfig: backendConfig, - } -} - -func (b *Backend) Start() { - fmt.Println("Listening on port", b.BackendConfig.Port) - http.ListenAndServe(fmt.Sprintf(":%d", b.BackendConfig.Port), nil) -} diff --git a/backend/backend/databases.go b/backend/backend/databases.go deleted file mode 100644 index bec6a67d..00000000 --- a/backend/backend/databases.go +++ /dev/null @@ -1,46 +0,0 @@ -package backend - -import ( - "context" - "os" - "strconv" - - "github.com/jackc/pgx/v5" - "github.com/redis/go-redis/v9" - - "art-peace-backend/config" -) - -type Databases struct { - DatabaseConfig *config.DatabaseConfig - - Redis *redis.Client - Postgres *pgx.Conn -} - -func NewDatabases(databaseConfig *config.DatabaseConfig) *Databases { - d := &Databases{} - d.DatabaseConfig = databaseConfig - - // Connect to Redis - d.Redis = redis.NewClient(&redis.Options{ - Addr: databaseConfig.Redis.Host + ":" + strconv.Itoa(databaseConfig.Redis.Port), - Password: "", // TODO: Read from env - DB: 0, - }) - - // Connect to Postgres - postgresConnString := "postgresql://" + databaseConfig.Postgres.User + ":" + os.Getenv("POSTGRES_PASSWORD") + "@" + databaseConfig.Postgres.Host + ":" + strconv.Itoa(databaseConfig.Postgres.Port) + "/" + databaseConfig.Postgres.Database - pgConn, err := pgx.Connect(context.Background(), postgresConnString) - if err != nil { - panic(err) - } - d.Postgres = pgConn - - return d -} - -func (d *Databases) Close() { - d.Redis.Close() - d.Postgres.Close(context.Background()) -} diff --git a/backend/config/backend.go b/backend/config/backend.go index 6294c791..d14c7975 100644 --- a/backend/config/backend.go +++ b/backend/config/backend.go @@ -6,40 +6,40 @@ import ( ) type BackendScriptsConfig struct { - PlacePixelDevnet string `json:"place_pixel_devnet"` - AddTemplateHashDevnet string `json:"add_template_hash_devnet"` + PlacePixelDevnet string `json:"place_pixel_devnet"` + AddTemplateHashDevnet string `json:"add_template_hash_devnet"` } type BackendConfig struct { - Host string `json:"host"` - Port int `json:"port"` - Scripts BackendScriptsConfig `json:"scripts"` + Host string `json:"host"` + Port int `json:"port"` + Scripts BackendScriptsConfig `json:"scripts"` } var DefaultBackendConfig = BackendConfig{ - Host: "localhost", - Port: 8080, - Scripts: BackendScriptsConfig{ - PlacePixelDevnet: "../scripts/place_pixel.sh", - AddTemplateHashDevnet: "../scripts/add_template_hash.sh", - }, + Host: "localhost", + Port: 8080, + Scripts: BackendScriptsConfig{ + PlacePixelDevnet: "../scripts/place_pixel.sh", + AddTemplateHashDevnet: "../scripts/add_template_hash.sh", + }, } var DefaultBackendConfigPath = "../configs/backend.config.json" func LoadBackendConfig(backendConfigPath string) (*BackendConfig, error) { - file, err := os.Open(backendConfigPath) - if err != nil { - return nil, err - } - defer file.Close() - - decoder := json.NewDecoder(file) - config := BackendConfig{} - err = decoder.Decode(&config) - if err != nil { - return nil, err - } - - return &config, nil + file, err := os.Open(backendConfigPath) + if err != nil { + return nil, err + } + defer file.Close() + + decoder := json.NewDecoder(file) + config := BackendConfig{} + err = decoder.Decode(&config) + if err != nil { + return nil, err + } + + return &config, nil } diff --git a/backend/config/canvas.go b/backend/config/canvas.go index b3d0d6dd..fba87167 100644 --- a/backend/config/canvas.go +++ b/backend/config/canvas.go @@ -6,49 +6,49 @@ import ( ) type CanvasSize struct { - Width uint `json:"width"` - Height uint `json:"height"` + Width uint `json:"width"` + Height uint `json:"height"` } type CanvasConfig struct { - Canvas CanvasSize `json:"canvas"` - Colors []string `json:"colors"` - ColorsBitWidth uint `json:"colors_bitwidth"` + Canvas CanvasSize `json:"canvas"` + Colors []string `json:"colors"` + ColorsBitWidth uint `json:"colors_bitwidth"` } var DefaultCanvasConfig = &CanvasConfig{ - Canvas: CanvasSize{ - Width: 100, - Height: 100, - }, - Colors: []string{ - "#000000", - "#FFFFFF", - "#FF0000", - "#00FF00", - "#0000FF", - "#FFFF00", - "#FF00FF", - "#00FFFF", - }, - ColorsBitWidth: 5, + Canvas: CanvasSize{ + Width: 100, + Height: 100, + }, + Colors: []string{ + "#000000", + "#FFFFFF", + "#FF0000", + "#00FF00", + "#0000FF", + "#FFFF00", + "#FF00FF", + "#00FFFF", + }, + ColorsBitWidth: 5, } var DefaultCanvasConfigPath = "../configs/canvas.config.json" func LoadCanvasConfig(canvasConfigPath string) (*CanvasConfig, error) { - canvasConfig := &CanvasConfig{} + canvasConfig := &CanvasConfig{} - canvasConfigFile, err := os.Open(canvasConfigPath) - if err != nil { - return nil, err - } - defer canvasConfigFile.Close() + canvasConfigFile, err := os.Open(canvasConfigPath) + if err != nil { + return nil, err + } + defer canvasConfigFile.Close() - jsonParser := json.NewDecoder(canvasConfigFile) - if err = jsonParser.Decode(canvasConfig); err != nil { - return nil, err - } + jsonParser := json.NewDecoder(canvasConfigFile) + if err = jsonParser.Decode(canvasConfig); err != nil { + return nil, err + } - return canvasConfig, nil + return canvasConfig, nil } diff --git a/backend/config/database.go b/backend/config/database.go index 922abb66..ff88c714 100644 --- a/backend/config/database.go +++ b/backend/config/database.go @@ -6,50 +6,50 @@ import ( ) type RedisConfig struct { - Host string `json:"host"` - Port int `json:"port"` + Host string `json:"host"` + Port int `json:"port"` } type PostgresConfig struct { - Host string `json:"host"` - Port int `json:"port"` - User string `json:"user"` - Database string `json:"database"` + Host string `json:"host"` + Port int `json:"port"` + User string `json:"user"` + Database string `json:"database"` } type DatabaseConfig struct { - Redis RedisConfig `json:"redis"` - Postgres PostgresConfig `json:"postgres"` + Redis RedisConfig `json:"redis"` + Postgres PostgresConfig `json:"postgres"` } var DefaultDatabaseConfig = DatabaseConfig{ - Redis: RedisConfig{ - Host: "localhost", - Port: 6379, - }, - Postgres: PostgresConfig{ - Host: "localhost", - Port: 5432, - User: "art-peace-user", - Database: "art-peace-db", - }, + Redis: RedisConfig{ + Host: "localhost", + Port: 6379, + }, + Postgres: PostgresConfig{ + Host: "localhost", + Port: 5432, + User: "art-peace-user", + Database: "art-peace-db", + }, } var DefaultDatabaseConfigPath = "../configs/database.config.json" func LoadDatabaseConfig(databaseConfigPath string) (*DatabaseConfig, error) { - file, err := os.Open(databaseConfigPath) - if err != nil { - return nil, err - } - defer file.Close() - - decoder := json.NewDecoder(file) - config := DatabaseConfig{} - err = decoder.Decode(&config) - if err != nil { - return nil, err - } - - return &config, nil + file, err := os.Open(databaseConfigPath) + if err != nil { + return nil, err + } + defer file.Close() + + decoder := json.NewDecoder(file) + config := DatabaseConfig{} + err = decoder.Decode(&config) + if err != nil { + return nil, err + } + + return &config, nil } diff --git a/backend/core/backend.go b/backend/core/backend.go new file mode 100644 index 00000000..9625ded8 --- /dev/null +++ b/backend/core/backend.go @@ -0,0 +1,33 @@ +package core + +import ( + "fmt" + "net/http" + + "github.com/gorilla/websocket" + + "github.com/keep-starknet-strange/art-peace/backend/config" +) + +type Backend struct { + Databases *Databases + WSConnections []*websocket.Conn + + CanvasConfig *config.CanvasConfig + BackendConfig *config.BackendConfig +} + +var ArtPeaceBackend *Backend + +func NewBackend(databases *Databases, canvasConfig *config.CanvasConfig, backendConfig *config.BackendConfig) *Backend { + return &Backend{ + Databases: databases, + CanvasConfig: canvasConfig, + BackendConfig: backendConfig, + } +} + +func (b *Backend) Start() { + fmt.Println("Listening on port", b.BackendConfig.Port) + http.ListenAndServe(fmt.Sprintf(":%d", b.BackendConfig.Port), nil) +} diff --git a/backend/core/databases.go b/backend/core/databases.go new file mode 100644 index 00000000..a53d59b0 --- /dev/null +++ b/backend/core/databases.go @@ -0,0 +1,46 @@ +package core + +import ( + "context" + "os" + "strconv" + + "github.com/jackc/pgx/v5" + "github.com/redis/go-redis/v9" + + "github.com/keep-starknet-strange/art-peace/backend/config" +) + +type Databases struct { + DatabaseConfig *config.DatabaseConfig + + Redis *redis.Client + Postgres *pgx.Conn +} + +func NewDatabases(databaseConfig *config.DatabaseConfig) *Databases { + d := &Databases{} + d.DatabaseConfig = databaseConfig + + // Connect to Redis + d.Redis = redis.NewClient(&redis.Options{ + Addr: databaseConfig.Redis.Host + ":" + strconv.Itoa(databaseConfig.Redis.Port), + Password: "", // TODO: Read from env + DB: 0, + }) + + // Connect to Postgres + postgresConnString := "postgresql://" + databaseConfig.Postgres.User + ":" + os.Getenv("POSTGRES_PASSWORD") + "@" + databaseConfig.Postgres.Host + ":" + strconv.Itoa(databaseConfig.Postgres.Port) + "/" + databaseConfig.Postgres.Database + pgConn, err := pgx.Connect(context.Background(), postgresConnString) + if err != nil { + panic(err) + } + d.Postgres = pgConn + + return d +} + +func (d *Databases) Close() { + d.Redis.Close() + d.Postgres.Close(context.Background()) +} diff --git a/backend/go.mod b/backend/go.mod index 905f3e82..b25549f6 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,4 +1,4 @@ -module art-peace-backend +module github.com/keep-starknet-strange/art-peace/backend go 1.22.0 diff --git a/backend/main.go b/backend/main.go index c3948bb7..1b03b991 100644 --- a/backend/main.go +++ b/backend/main.go @@ -3,15 +3,15 @@ package main import ( "flag" - "art-peace-backend/backend" - "art-peace-backend/config" - "art-peace-backend/routes" + "github.com/keep-starknet-strange/art-peace/backend/config" + "github.com/keep-starknet-strange/art-peace/backend/core" + "github.com/keep-starknet-strange/art-peace/backend/routes" ) func main() { 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") + backendConfigFilename := flag.String("backend-config", config.DefaultBackendConfigPath, "Backend config file") flag.Parse() canvasConfig, err := config.LoadCanvasConfig(*canvasConfigFilename) @@ -24,16 +24,16 @@ func main() { panic(err) } - backendConfig, err := config.LoadBackendConfig(*backendConfigFilename) - if err != nil { - panic(err) - } + backendConfig, err := config.LoadBackendConfig(*backendConfigFilename) + if err != nil { + panic(err) + } - databases := backend.NewDatabases(databaseConfig) + databases := core.NewDatabases(databaseConfig) defer databases.Close() - routes.InitRoutes() + routes.InitRoutes() - backend.ArtPeaceBackend = backend.NewBackend(databases, canvasConfig, backendConfig) - backend.ArtPeaceBackend.Start() + core.ArtPeaceBackend = core.NewBackend(databases, canvasConfig, backendConfig) + core.ArtPeaceBackend.Start() } diff --git a/backend/routes/canvas.go b/backend/routes/canvas.go index b70dd27b..22e8a2f0 100644 --- a/backend/routes/canvas.go +++ b/backend/routes/canvas.go @@ -5,41 +5,40 @@ import ( "fmt" "net/http" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitCanvasRoutes() { - http.HandleFunc("/initCanvas", initCanvas) - http.HandleFunc("/getCanvas", getCanvas) + http.HandleFunc("/initCanvas", initCanvas) + http.HandleFunc("/getCanvas", getCanvas) } func initCanvas(w http.ResponseWriter, r *http.Request) { - // TODO: Check if canvas already exists - totalBitSize := backend.ArtPeaceBackend.CanvasConfig.Canvas.Width * backend.ArtPeaceBackend.CanvasConfig.Canvas.Height * backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth - totalByteSize := (totalBitSize / 8) - if totalBitSize % 8 != 0 { - // Round up to nearest byte - totalByteSize += 1 - } - - canvas := make([]byte, totalByteSize) - ctx := context.Background() - err := backend.ArtPeaceBackend.Databases.Redis.Set(ctx, "canvas", canvas, 0).Err() - if err != nil { - panic(err) - } - - fmt.Println("Canvas initialized") + // TODO: Check if canvas already exists + totalBitSize := core.ArtPeaceBackend.CanvasConfig.Canvas.Width * core.ArtPeaceBackend.CanvasConfig.Canvas.Height * core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth + totalByteSize := (totalBitSize / 8) + if totalBitSize%8 != 0 { + // Round up to nearest byte + totalByteSize += 1 + } + + canvas := make([]byte, totalByteSize) + ctx := context.Background() + err := core.ArtPeaceBackend.Databases.Redis.Set(ctx, "canvas", canvas, 0).Err() + if err != nil { + panic(err) + } + + fmt.Println("Canvas initialized") } - func getCanvas(w http.ResponseWriter, r *http.Request) { - ctx := context.Background() - val, err := backend.ArtPeaceBackend.Databases.Redis.Get(ctx, "canvas").Result() - if err != nil { - panic(err) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte(val)) + ctx := context.Background() + val, err := core.ArtPeaceBackend.Databases.Redis.Get(ctx, "canvas").Result() + if err != nil { + panic(err) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte(val)) } diff --git a/backend/routes/contract.go b/backend/routes/contract.go index 532f9b04..d01f6dd6 100644 --- a/backend/routes/contract.go +++ b/backend/routes/contract.go @@ -7,23 +7,23 @@ import ( ) func InitContractRoutes() { - http.HandleFunc("/getContractAddress", getContractAddress) - http.HandleFunc("/setContractAddress", setContractAddress) + http.HandleFunc("/getContractAddress", getContractAddress) + http.HandleFunc("/setContractAddress", setContractAddress) } func getContractAddress(w http.ResponseWriter, r *http.Request) { - contractAddress := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - w.Write([]byte(contractAddress)) + contractAddress := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") + w.Write([]byte(contractAddress)) } func setContractAddress(w http.ResponseWriter, r *http.Request) { - // TODO: Add authentication - data, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid request")) - return - } - os.Setenv("ART_PEACE_CONTRACT_ADDRESS", string(data)) - w.Write([]byte("Contract address set successfully")) + // TODO: Add authentication + data, err := ioutil.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Invalid request")) + return + } + os.Setenv("ART_PEACE_CONTRACT_ADDRESS", string(data)) + w.Write([]byte("Contract address set successfully")) } diff --git a/backend/routes/indexer.go b/backend/routes/indexer.go index d4a91231..a137412f 100644 --- a/backend/routes/indexer.go +++ b/backend/routes/indexer.go @@ -10,11 +10,11 @@ import ( "github.com/gorilla/websocket" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitIndexerRoutes() { - http.HandleFunc("/consumeIndexerMsg", consumeIndexerMsg) + http.HandleFunc("/consumeIndexerMsg", consumeIndexerMsg) } // TODO: Clean up @@ -57,86 +57,86 @@ func InitIndexerRoutes() { // TODO: User might miss some messages between loading canvas and connecting to websocket? func consumeIndexerMsg(w http.ResponseWriter, r *http.Request) { - requestBody, err := io.ReadAll(r.Body) - if err != nil { - fmt.Println("Error reading request body: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + requestBody, err := io.ReadAll(r.Body) + if err != nil { + fmt.Println("Error reading request body: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - // TODO: Parse message fully, check block status, number, ... - reqBody := map[string]interface{}{} - err = json.Unmarshal(requestBody, &reqBody) - if err != nil { - fmt.Println("Error unmarshalling request body: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + // TODO: Parse message fully, check block status, number, ... + reqBody := map[string]interface{}{} + err = json.Unmarshal(requestBody, &reqBody) + if err != nil { + fmt.Println("Error unmarshalling request body: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - address := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[1] - address = address.(string)[2:] - posHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[2] - dayIdxHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[3] - colorHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["data"].([]interface{})[0] + address := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[1] + address = address.(string)[2:] + posHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[2] + dayIdxHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[3] + colorHex := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{})[0].(map[string]interface{})["event"].(map[string]interface{})["data"].([]interface{})[0] - // Convert hex to int - position, err := strconv.ParseInt(posHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting position hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - dayIdx, err := strconv.ParseInt(dayIdxHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting day index hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - color, err := strconv.ParseInt(colorHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting color hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + // Convert hex to int + position, err := strconv.ParseInt(posHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting position hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + dayIdx, err := strconv.ParseInt(dayIdxHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting day index hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + color, err := strconv.ParseInt(colorHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting color hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - bitfieldType := "u" + strconv.Itoa(int(backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) - pos := uint(position) * backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth + bitfieldType := "u" + strconv.Itoa(int(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) + pos := uint(position) * core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth - fmt.Println("Pixel indexed with position: ", position, " and color: ", color) + fmt.Println("Pixel indexed with position: ", position, " and color: ", color) - // Set pixel in redis - ctx := context.Background() - err = backend.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "SET", bitfieldType, pos, color).Err() - if err != nil { - panic(err) - } + // Set pixel in redis + ctx := context.Background() + err = core.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "SET", bitfieldType, pos, color).Err() + if err != nil { + panic(err) + } - // Set pixel in postgres - _, err = backend.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO Pixels (address, position, day, color) VALUES ($1, $2, $3, $4)", address, position, dayIdx, color) - if err != nil { - fmt.Println("Error inserting pixel into postgres: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + // Set pixel in postgres + _, err = core.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO Pixels (address, position, day, color) VALUES ($1, $2, $3, $4)", address, position, dayIdx, color) + if err != nil { + fmt.Println("Error inserting pixel into postgres: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - // Send message to all connected clients - var message = map[string]interface{}{ - "position": position, - "color": color, - } - messageBytes, err := json.Marshal(message) - if err != nil { - fmt.Println("Error marshalling message: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - for idx, conn := range backend.ArtPeaceBackend.WSConnections { - if err := conn.WriteMessage(websocket.TextMessage, messageBytes); err != nil { - fmt.Println(err) - // TODO: Should we always remove connection? - // Remove connection - conn.Close() - backend.ArtPeaceBackend.WSConnections = append(backend.ArtPeaceBackend.WSConnections[:idx], backend.ArtPeaceBackend.WSConnections[idx+1:]...) - } - } + // Send message to all connected clients + var message = map[string]interface{}{ + "position": position, + "color": color, + } + messageBytes, err := json.Marshal(message) + if err != nil { + fmt.Println("Error marshalling message: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + for idx, conn := range core.ArtPeaceBackend.WSConnections { + if err := conn.WriteMessage(websocket.TextMessage, messageBytes); err != nil { + fmt.Println(err) + // TODO: Should we always remove connection? + // Remove connection + conn.Close() + core.ArtPeaceBackend.WSConnections = append(core.ArtPeaceBackend.WSConnections[:idx], core.ArtPeaceBackend.WSConnections[idx+1:]...) + } + } } diff --git a/backend/routes/pixel.go b/backend/routes/pixel.go index 99560601..59656372 100644 --- a/backend/routes/pixel.go +++ b/backend/routes/pixel.go @@ -10,99 +10,99 @@ import ( "os/exec" "strconv" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitPixelRoutes() { - http.HandleFunc("/getPixel", getPixel) - http.HandleFunc("/getPixelInfo", getPixelInfo) - http.HandleFunc("/placePixelDevnet", placePixelDevnet) - http.HandleFunc("/placePixelRedis", placePixelRedis) + http.HandleFunc("/getPixel", getPixel) + http.HandleFunc("/getPixelInfo", getPixelInfo) + http.HandleFunc("/placePixelDevnet", placePixelDevnet) + http.HandleFunc("/placePixelRedis", placePixelRedis) } func getPixel(w http.ResponseWriter, r *http.Request) { - position, err := strconv.Atoi(r.URL.Query().Get("position")) - if err != nil { - // TODO: panic or return error? - panic(err) - } - bitfieldType := "u" + strconv.Itoa(int(backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) - pos := uint(position) * backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth + position, err := strconv.Atoi(r.URL.Query().Get("position")) + if err != nil { + // TODO: panic or return error? + panic(err) + } + bitfieldType := "u" + strconv.Itoa(int(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) + pos := uint(position) * core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth - ctx := context.Background() - val, err := backend.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "GET", bitfieldType, pos).Result() - if err != nil { - panic(err) - } + ctx := context.Background() + val, err := core.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "GET", bitfieldType, pos).Result() + if err != nil { + panic(err) + } - w.Header().Set("Access-Control-Allow-Origin", "*") - // TODO: Check this - w.Write([]byte(strconv.Itoa(int(val[0])))) + w.Header().Set("Access-Control-Allow-Origin", "*") + // TODO: Check this + w.Write([]byte(strconv.Itoa(int(val[0])))) } func getPixelInfo(w http.ResponseWriter, r *http.Request) { - position := r.URL.Query().Get("position") - w.Header().Set("Access-Control-Allow-Origin", "*") + position := r.URL.Query().Get("position") + w.Header().Set("Access-Control-Allow-Origin", "*") - // Get pixel info from postgres - var address string - err := backend.ArtPeaceBackend.Databases.Postgres.QueryRow(context.Background(), "SELECT address FROM Pixels WHERE position = $1 ORDER BY time DESC LIMIT 1", position).Scan(&address) - if err != nil { - w.Write([]byte("0000000000000000000000000000000000000000000000000000000000000000")) - } else { - w.Write([]byte(address)) - } + // Get pixel info from postgres + var address string + err := core.ArtPeaceBackend.Databases.Postgres.QueryRow(context.Background(), "SELECT address FROM Pixels WHERE position = $1 ORDER BY time DESC LIMIT 1", position).Scan(&address) + if err != nil { + w.Write([]byte("0000000000000000000000000000000000000000000000000000000000000000")) + } else { + w.Write([]byte(address)) + } } func placePixelDevnet(w http.ResponseWriter, r *http.Request) { - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - var jsonBody map[string]string - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + var jsonBody map[string]string + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } - position, err := strconv.Atoi(jsonBody["position"]) - if err != nil { - panic(err) - } + position, err := strconv.Atoi(jsonBody["position"]) + if err != nil { + panic(err) + } - shellCmd := backend.ArtPeaceBackend.BackendConfig.Scripts.PlacePixelDevnet - contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - - cmd := exec.Command(shellCmd, contract, "place_pixel", strconv.Itoa(position), jsonBody["color"]) - _, err = cmd.Output() - if err != nil { - fmt.Println("Error executing shell command: ", err) - panic(err) - } + shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.PlacePixelDevnet + contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("Pixel placed")) + cmd := exec.Command(shellCmd, contract, "place_pixel", strconv.Itoa(position), jsonBody["color"]) + _, err = cmd.Output() + if err != nil { + fmt.Println("Error executing shell command: ", err) + panic(err) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("Pixel placed")) } func placePixelRedis(w http.ResponseWriter, r *http.Request) { - // TODO: Only allow mods to place pixels on redis instance - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - var jsonBody map[string]uint - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } - position := jsonBody["position"] - color := jsonBody["color"] - bitfieldType := "u" + strconv.Itoa(int(backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) - pos := position * backend.ArtPeaceBackend.CanvasConfig.ColorsBitWidth + // TODO: Only allow mods to place pixels on redis instance + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + var jsonBody map[string]uint + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } + position := jsonBody["position"] + color := jsonBody["color"] + bitfieldType := "u" + strconv.Itoa(int(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth)) + pos := position * core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth - ctx := context.Background() - err = backend.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "SET", bitfieldType, pos, color).Err() - if err != nil { - panic(err) - } + ctx := context.Background() + err = core.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "SET", bitfieldType, pos, color).Err() + if err != nil { + panic(err) + } } diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 9ae3fe2d..67bdf249 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go @@ -1,11 +1,11 @@ package routes func InitRoutes() { - InitIndexerRoutes() - InitCanvasRoutes() - InitPixelRoutes() - InitWebsocketRoutes() - InitTemplateRoutes() - InitUserRoutes() - InitContractRoutes() + InitIndexerRoutes() + InitCanvasRoutes() + InitPixelRoutes() + InitWebsocketRoutes() + InitTemplateRoutes() + InitUserRoutes() + InitContractRoutes() } diff --git a/backend/routes/templates.go b/backend/routes/templates.go index 48c1f4a1..d1717970 100644 --- a/backend/routes/templates.go +++ b/backend/routes/templates.go @@ -9,113 +9,112 @@ import ( "os" "os/exec" - "github.com/NethermindEth/juno/core/crypto" - "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/core/crypto" + "github.com/NethermindEth/juno/core/felt" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitTemplateRoutes() { - http.HandleFunc("/addTemplateImg", addTemplateImg) - http.HandleFunc("/addTemplateData", addTemplateData) - http.HandleFunc("/addTemplateHashDevnet", addTemplateHashDevnet) + http.HandleFunc("/addTemplateImg", addTemplateImg) + http.HandleFunc("/addTemplateData", addTemplateData) + http.HandleFunc("/addTemplateHashDevnet", addTemplateHashDevnet) } // TODO: Add specific location for template images func hashTemplateImage(pixelData []byte) string { - var data[]*felt.Felt - for _, pixel := range pixelData { - f := new(felt.Felt).SetUint64(uint64(pixel)) - data = append(data, f) - } - hash := crypto.PoseidonArray(data...) - return hash.String() + var data []*felt.Felt + for _, pixel := range pixelData { + f := new(felt.Felt).SetUint64(uint64(pixel)) + data = append(data, f) + } + hash := crypto.PoseidonArray(data...) + return hash.String() } func imageToPixelData(imageData []byte) []byte { - // TODO: Convert image data to pixel data using approximation - // Output should be a byte array with color indexes - return []byte{0, 1, 1, 2, 2, 3} + // TODO: Convert image data to pixel data using approximation + // Output should be a byte array with color indexes + return []byte{0, 1, 1, 2, 2, 3} } func addTemplateImg(w http.ResponseWriter, r *http.Request) { - // TODO: Limit file size / proportions between 5x5 and 64x64 - // Passed like this curl -F "image=@art-peace-low-res-goose.jpg" http://localhost:8080/addTemplateImg - file, _, err := r.FormFile("image") - if err != nil { - panic(err) - } - defer file.Close() - - // Create a temporary file to store the uploaded file - // TODO: change location & determine valid file types - tempFile, err := ioutil.TempFile("temp-images", "upload-*.png") - if err != nil { - panic(err) - } - defer tempFile.Close() - - // Read all data from the uploaded file and write it to the temporary file - fileBytes, err := ioutil.ReadAll(file) - if err != nil { - panic(err) - } - tempFile.Write(fileBytes) - - r.Body.Close() - - imageData := imageToPixelData(fileBytes) - hash := hashTemplateImage(imageData) - // TODO: Store image hash and pixel data in postgres database - - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte(hash)) + // TODO: Limit file size / proportions between 5x5 and 64x64 + // Passed like this curl -F "image=@art-peace-low-res-goose.jpg" http://localhost:8080/addTemplateImg + file, _, err := r.FormFile("image") + if err != nil { + panic(err) + } + defer file.Close() + + // Create a temporary file to store the uploaded file + // TODO: change location & determine valid file types + tempFile, err := ioutil.TempFile("temp-images", "upload-*.png") + if err != nil { + panic(err) + } + defer tempFile.Close() + + // Read all data from the uploaded file and write it to the temporary file + fileBytes, err := ioutil.ReadAll(file) + if err != nil { + panic(err) + } + tempFile.Write(fileBytes) + + r.Body.Close() + + imageData := imageToPixelData(fileBytes) + hash := hashTemplateImage(imageData) + // TODO: Store image hash and pixel data in postgres database + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte(hash)) } func addTemplateData(w http.ResponseWriter, r *http.Request) { - // Passed as byte array w/ color indexes instead of image - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - var jsonBody map[string]string - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } - - hash := hashTemplateImage([]byte(jsonBody["image"])) - // TODO: Store image hash and pixel data in database - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte(hash)) + // Passed as byte array w/ color indexes instead of image + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + var jsonBody map[string]string + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } + + hash := hashTemplateImage([]byte(jsonBody["image"])) + // TODO: Store image hash and pixel data in database + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte(hash)) } func addTemplateHashDevnet(w http.ResponseWriter, r *http.Request) { - // TODO: Disable this in production - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - var jsonBody map[string]string - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } - - // TODO: Create this script - shellCmd := backend.ArtPeaceBackend.BackendConfig.Scripts.AddTemplateHashDevnet - // TODO: remove contract from jsonBody - contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - cmd := exec.Command(shellCmd, contract, "add_template", jsonBody["hash"]) - _, err = cmd.Output() - if err != nil { - fmt.Println("Error executing shell command: ", err) - panic(err) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("Hash added to devnet")) + // TODO: Disable this in production + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + var jsonBody map[string]string + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } + + // TODO: Create this script + shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.AddTemplateHashDevnet + // TODO: remove contract from jsonBody + contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") + cmd := exec.Command(shellCmd, contract, "add_template", jsonBody["hash"]) + _, err = cmd.Output() + if err != nil { + fmt.Println("Error executing shell command: ", err) + panic(err) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("Hash added to devnet")) } diff --git a/backend/routes/user.go b/backend/routes/user.go index 85b66c94..f03d018a 100644 --- a/backend/routes/user.go +++ b/backend/routes/user.go @@ -4,25 +4,25 @@ import ( "context" "net/http" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitUserRoutes() { - http.HandleFunc("/getExtraPixels", getExtraPixels) + http.HandleFunc("/getExtraPixels", getExtraPixels) } func getExtraPixels(w http.ResponseWriter, r *http.Request) { - user := r.URL.Query().Get("address") + user := r.URL.Query().Get("address") - var available string - err := backend.ArtPeaceBackend.Databases.Postgres.QueryRow(context.Background(), "SELECT available FROM ExtraPixels WHERE address = $1", user).Scan(&available); - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } + var available string + err := core.ArtPeaceBackend.Databases.Postgres.QueryRow(context.Background(), "SELECT available FROM ExtraPixels WHERE address = $1", user).Scan(&available) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } - w.Header().Set("Access-Control-Allow-Origin", "*") - w.WriteHeader(http.StatusOK) - w.Write([]byte(available)) + w.Header().Set("Access-Control-Allow-Origin", "*") + w.WriteHeader(http.StatusOK) + w.Write([]byte(available)) } diff --git a/backend/routes/websocket.go b/backend/routes/websocket.go index e262b8bc..d62fa75a 100644 --- a/backend/routes/websocket.go +++ b/backend/routes/websocket.go @@ -6,39 +6,39 @@ import ( "github.com/gorilla/websocket" - "art-peace-backend/backend" + "github.com/keep-starknet-strange/art-peace/backend/core" ) func InitWebsocketRoutes() { - http.HandleFunc("/ws", wsEndpoint) + http.HandleFunc("/ws", wsEndpoint) } var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, + ReadBufferSize: 1024, + WriteBufferSize: 1024, } func wsReader(conn *websocket.Conn) { - for { - // TODO: exit on close in backend? - messageType, p, err := conn.ReadMessage() - if err != nil { - fmt.Println(err) - return - } - fmt.Println("WS message received: ", messageType, string(p)) - } + for { + // TODO: exit on close in backend? + messageType, p, err := conn.ReadMessage() + if err != nil { + fmt.Println(err) + return + } + fmt.Println("WS message received: ", messageType, string(p)) + } } func wsEndpoint(w http.ResponseWriter, r *http.Request) { - upgrader.CheckOrigin = func(r *http.Request) bool { return true } + upgrader.CheckOrigin = func(r *http.Request) bool { return true } - ws, err := upgrader.Upgrade(w, r, nil) - if err != nil { - fmt.Println(err) - } + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + fmt.Println(err) + } - fmt.Println("Client Connected") - backend.ArtPeaceBackend.WSConnections = append(backend.ArtPeaceBackend.WSConnections, ws) - wsReader(ws) + fmt.Println("Client Connected") + core.ArtPeaceBackend.WSConnections = append(core.ArtPeaceBackend.WSConnections, ws) + wsReader(ws) } diff --git a/tests/integration/docker/deploy.sh b/tests/integration/docker/deploy.sh index ada9913b..f517daa5 100755 --- a/tests/integration/docker/deploy.sh +++ b/tests/integration/docker/deploy.sh @@ -47,8 +47,8 @@ COLOR_COUNT=$(jq -r '.colors[]' $CANVAS_CONFIG | wc -l | tr -d ' ') COLORS=$(jq -r '.colors[]' $CANVAS_CONFIG | sed 's/^/0x/') END_TIME=3000000000 -# [WIDTH, HEIGHT, TIME_BETWEEN_PIXELS, COLOR_PALLETE_LEN, COLORS, END_TIME, DAILY_QUESTS_LEN, D AILY_QUESTS, DAILY_QUESTS_LEN, MAIN_QUESTS] -CALLDATA=$(echo -n $WIDTH $HEIGHT $PLACE_DELAY $COLOR_COUNT $COLORS $END_TIME 0 0) +# [WIDTH, HEIGHT, TIME_BETWEEN_PIXELS, COLOR_PALLETE_LEN, COLORS, END_TIME, DAILY_QUESTS_LEN, D AILY_QUESTS, DAILY_QUESTS_LEN, MAIN_QUESTS, NFT_CONTRACT] +CALLDATA=$(echo -n $WIDTH $HEIGHT $PLACE_DELAY $COLOR_COUNT $COLORS $END_TIME 0 0 0) # TODO: calldata passed as parameters echo "Deploying contract \"$CLASS_NAME\"..." diff --git a/tests/integration/local/deploy.sh b/tests/integration/local/deploy.sh index 54d7f00a..cf398e4e 100755 --- a/tests/integration/local/deploy.sh +++ b/tests/integration/local/deploy.sh @@ -48,7 +48,7 @@ COLORS=$(jq -r '.colors[]' $CANVAS_CONFIG | sed 's/^/0x/') END_TIME=3000000000 # [WIDTH, HEIGHT, TIME_BETWEEN_PIXELS, COLOR_PALLETE_LEN, COLORS, END_TIME, DAILY_QUESTS_LEN, DAILY_QUESTS, DAILY_QUESTS_LEN, MAIN_QUESTS] -CALLDATA=$(echo -n $WIDTH $HEIGHT $PLACE_DELAY $COLOR_COUNT $COLORS $END_TIME 0 0) +CALLDATA=$(echo -n $WIDTH $HEIGHT $PLACE_DELAY $COLOR_COUNT $COLORS $END_TIME 0 0 0) echo "Calldata: $CALLDATA" # TODO: calldata passed as parameters echo "Deploying contract \"$CLASS_NAME\"..."