Initial commit

This commit is contained in:
Yaser
2026-08-13 20:20:47 +03:30
commit 78a0c832d7
33 changed files with 3399 additions and 0 deletions

208
cmd/rango/rango.go Normal file
View File

@@ -0,0 +1,208 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"strings"
"time"
"math/rand"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/openware/rango/pkg/amqp"
"github.com/openware/rango/pkg/auth"
"github.com/openware/rango/pkg/metrics"
"github.com/openware/rango/pkg/routing"
)
var (
wsAddr = flag.String("ws-addr", "", "http service address")
amqpAddr = flag.String("amqp-addr", "", "AMQP server address")
pubKey = flag.String("pubKey", "config/ed25519-key.pub", "Path to public key")
exName = flag.String("exchange", "peatio.events.ranger", "Exchange name of upstream messages")
)
const prefix = "Bearer "
type httpHanlder func(w http.ResponseWriter, r *http.Request)
func token(r *http.Request) string {
authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(string(authHeader), prefix) {
return ""
}
return authHeader[len(prefix):]
}
func authHandler(h httpHanlder, validator auth.Validator, mustAuth bool) httpHanlder {
return func(w http.ResponseWriter, r *http.Request) {
claims, err := validator.ParseAndValidate(token(r))
if err != nil && mustAuth {
w.WriteHeader(http.StatusUnauthorized)
return
}
if err == nil {
r.Header.Set("JwtUID", claims.UID)
r.Header.Set("JwtRole", claims.Role)
} else {
r.Header.Del("JwtUID")
r.Header.Del("JwtRole")
}
h(w, r)
}
}
func setupLogger() {
logLevel, ok := os.LookupEnv("LOG_LEVEL")
if ok {
level, err := zerolog.ParseLevel(strings.ToLower(logLevel))
if err != nil {
panic(err)
}
zerolog.SetGlobalLevel(level)
return
}
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
func getEnv(name, value string) string {
v := os.Getenv(name)
if v == "" {
return value
}
return v
}
func getAMQPConnectionURL() string {
if *amqpAddr != "" {
return *amqpAddr
}
user := getEnv("RABBITMQ_USER", "guest")
pass := getEnv("RABBITMQ_PASSWORD", "guest")
host := getEnv("RABBITMQ_HOST", "localhost")
port := getEnv("RABBITMQ_PORT", "5672")
return fmt.Sprintf("amqp://%s:%s@%s:%s", user, pass, host, port)
}
func getServerAddress() string {
if *wsAddr != "" {
return *wsAddr
}
host := getEnv("RANGER_HOST", "0.0.0.0")
port := getEnv("RANGER_PORT", "8080")
return fmt.Sprintf("%s:%s", host, port)
}
func getRBACConfig() map[string][]string {
envs := os.Environ()
rbacEnv := filterPrefixed("RANGO_RBAC_", envs)
return envToMatrix(rbacEnv, "RANGO_RBAC_")
}
func envToMatrix(env []string, trimPrefix string) map[string][]string {
matr := make(map[string][]string)
for _, rec := range env {
kv := strings.Split(rec, "=")
key := strings.ToLower(strings.TrimPrefix(kv[0], trimPrefix))
value := strings.Split(kv[1], ",")
matr[key] = value
}
return matr
}
func filterPrefixed(prefix string, arr []string) []string {
var res []string
for _, rec := range arr {
if strings.HasPrefix(rec, prefix) {
res = append(res, rec)
}
}
return res
}
func main() {
flag.Parse()
setupLogger()
metrics.Enable()
rbac := getRBACConfig()
hub := routing.NewHub(rbac)
validator, err := auth.LoadValidator(*pubKey)
if err != nil {
log.Error().Msgf("Loading public key failed: %s", err.Error())
time.Sleep(2 * time.Second)
return
}
log.Info().Msgf("JWT validator mode: %s", validator.Mode)
rand.Seed(time.Now().UnixNano())
globalQName := fmt.Sprintf("rango.instance.%d", rand.Int())
privateQName := fmt.Sprintf("rango.instance.private-%d", rand.Int())
// Establish AMQP session for all non private events
globalMq, err := amqp.NewAMQPSession(getAMQPConnectionURL())
if err != nil {
log.Fatal().Msgf("creating new AMQP session failed: %s", err.Error())
return
}
err = globalMq.Stream(*exName, globalQName, "#", hub.SkipPrivateMsg)
defer globalMq.Close(globalQName)
if err != nil {
log.Fatal().Msgf("AMQP init failed: %s", err.Error())
return
}
// Establish AMQP session for private events
privateMq, err := amqp.NewAMQPSession(getAMQPConnectionURL())
if err != nil {
log.Fatal().Msgf("creating new AMQP session failed: %s", err.Error())
return
}
err = privateMq.Stream(*exName, privateQName, "private.#", hub.ReceiveMsg)
defer privateMq.Close(privateQName)
if err != nil {
log.Fatal().Msgf("AMQP init failed: %s", err.Error())
return
}
go hub.ListenWebsocketEvents()
wsHandler := func(w http.ResponseWriter, r *http.Request) {
routing.NewClient(hub, w, r)
}
http.HandleFunc("/private", authHandler(wsHandler, validator, true))
http.HandleFunc("/public", authHandler(wsHandler, validator, false))
http.HandleFunc("/", authHandler(wsHandler, validator, false))
go http.ListenAndServe(":4242", promhttp.Handler())
log.Printf("Listenning on %s", getServerAddress())
err = http.ListenAndServe(getServerAddress(), nil)
if err != nil {
log.Fatal().Msg("ListenAndServe failed: " + err.Error())
}
}