2025-03-25 03:52:30 -04:00

185 lines
5.7 KiB
Go

package main
import (
"fmt"
"log"
"math/big"
"net/http"
"os"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/blockchain"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/feedback"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/identity"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/ipfs"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/moderation"
"4vif5i.gitea.cloud/numenor-labs/discourse/backend/perspective"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var (
rpcURL = os.Getenv("RPC_URL")
contractAddress = os.Getenv("CONTRACT_ADDRESS")
privateKey = os.Getenv("PRIVATE_KEY")
redisAddr = getEnv("REDIS_ADDR", "localhost:6379")
redisPassword = getEnv("REDIS_PASSWORD", "")
redisDB = 0
dbDSN = getEnv("DATABASE_URL", "postgres://postgres:postgres@localhost:5432/voxpop?sslmode=disable")
)
// getEnv gets an environment variable or returns a default value
func getEnv(key, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}
func main() {
// Connect to Sepolia
client, err := ethclient.Dial(rpcURL)
if err != nil {
log.Fatalf("Failed to connect to Ethereum client: %v", err)
}
// Connect to Redis
redisClient := redis.NewClient(&redis.Options{
Addr: redisAddr,
Password: redisPassword,
DB: redisDB,
})
// Connect to PostgreSQL
db, err := gorm.Open(postgres.Open(dbDSN), &gorm.Config{})
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
log.Println("Connected to PostgreSQL database")
// Set up HTTP server
router := gin.Default()
// Initialize the verification handler
verificationHandler := identity.NewVerificationHandler()
// Register the verification routes
verificationHandler.RegisterRoutes(router)
// Initialize the IPFS service (or use mock for development)
var ipfsService perspective.IPFSServiceInterface
pinataProd := os.Getenv("PINATA_PRODUCTION")
if pinataProd == "true" {
ipfsServiceReal, err := ipfs.NewIPFSService()
if err != nil {
log.Printf("Warning: Failed to initialize Pinata IPFS service: %v", err)
log.Println("Falling back to mock IPFS service")
ipfsService = ipfs.NewMockIPFSService()
} else {
ipfsService = ipfsServiceReal
log.Println("Initialized Pinata IPFS service")
}
} else {
ipfsService = ipfs.NewMockIPFSService()
log.Println("Using mock IPFS service")
}
// Initialize the perspective service and handler
perspectiveService := perspective.NewPerspectiveService(redisClient, db, ipfsService)
perspectiveHandler := perspective.NewPerspectiveHandler(perspectiveService)
// Register the perspective routes
perspectiveHandler.RegisterRoutes(router)
// Initialize the moderation service and handler
moderationService := moderation.NewModerationService(db)
moderationHandler := moderation.NewModerationHandler(moderationService)
// Register the moderation routes
moderationHandler.RegisterRoutes(router)
// Initialize the blockchain service and handler
blockchainService, err := blockchain.NewBlockchainService()
if err != nil {
log.Fatalf("Failed to initialize blockchain service: %v", err)
}
defer blockchainService.Close()
blockchainHandler := blockchain.NewHandler(blockchainService)
// Register the blockchain routes
blockchainHandler.RegisterRoutes(router)
// Existing feedback submission endpoint
router.OPTIONS(
"/submit-feedback", func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type")
c.Status(http.StatusOK)
},
)
router.POST(
"/submit-feedback", func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type")
var request struct {
Proof string `json:"proof"`
Feedback string `json:"feedback"`
}
if err := c.BindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
return
}
// Mocked ZKP verification
if request.Proof != "valid_proof" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid proof"})
return
}
privateKeyECDSA, err := crypto.HexToECDSA(privateKey)
if err != nil {
fmt.Println("Failed to parse private key:", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to parse private key"})
return
}
// Create the transactor (chain ID 11155111 is for Sepolia testnet, adjust as needed)
auth, err := bind.NewKeyedTransactorWithChainID(privateKeyECDSA, big.NewInt(11155111))
if err != nil {
log.Fatalf("Failed to create transactor: %v", err)
}
// Instantiate the contract
contract, err := feedback.NewFeedback(common.HexToAddress(contractAddress), client)
if err != nil {
fmt.Println("Failed to instantiate contract:", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to instantiate contract"})
return
}
// Submit feedback to blockchain
tx, err := contract.SubmitFeedback(auth, request.Feedback)
if err != nil {
fmt.Println("Failed to submit feedback:", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to submit feedback"})
return
}
fmt.Println("Submitted feedback:", tx.Hash().Hex())
c.JSON(http.StatusOK, gin.H{"transaction": tx.Hash().Hex()})
},
)
log.Println("Server running on :3000")
router.Run(":3000")
}