package main import ( "bytes" "encoding/json" "fmt" "log" "net/http" "os" "strings" "sync" "github.com/lesismal/llib/std/crypto/tls" "github.com/deroproject/derohe/globals" "github.com/lesismal/nbio/nbhttp" "github.com/lesismal/nbio/nbhttp/websocket" "dero-swap/cfg" "dero-swap/coin" "dero-swap/dero" ) type WS_Message struct { ID uint64 `json:"id"` Method string `json:"method"` Params any `json:"params,omitempty"` Result any `json:"result"` } var WSConnections sync.Map // swap other coins to Dero func Dero_Swap(request coin.Swap_Request) (response coin.Swap_Response) { var err error // check if destination wallet is valid. Registered usernames can also be used. if strings.HasPrefix(request.DeroAddr, "dero1") || strings.HasPrefix(request.DeroAddr, "deroi") { _, err = globals.ParseValidateAddress(request.DeroAddr) } else { if addr := dero.CheckAddress(request.DeroAddr); addr != "" { request.DeroAddr = addr } else { err = fmt.Errorf("invalid address") } } // basic checks if request.Amount == 0 || err != nil { response.Error = "invalid request" return } // prevent users from creating too many swap requests if Delay.CheckUser(request.DeroAddr) { response.Error = "2 minutes wait time triggered" return } // check if pair is enabled and available pair := request.Pair if !coin.IsPairEnabled(pair) || !IsPairAvailable[pair] { response.Error = fmt.Sprintf("%s swap currently not possible", pair) return } // create swap err = XTCSwap(pair, request.DeroAddr, coin.RoundFloat(request.Amount, 5), &response) if err != nil { response.Error = err.Error() log.Println(err) } else { Delay.AddUser(request.DeroAddr) } response.Request = request return response } // swap Dero to other coins func Reverse_Swap(request coin.Swap_Request) (response coin.Swap_Response) { var err error // prevent users from creating too many swap requests if Delay.CheckUser(request.DeroAddr) { response.Error = "2 minutes wait time triggered" return } // check if pair is enabled and available pair := request.Pair if !coin.IsPairEnabled(pair) || !IsPairAvailable[pair] { response.Error = fmt.Sprintf("%s swap currently not possible", pair) return } response.Deposit = coin.RoundFloat(request.Amount, 5) // create swap err = DeroXTCSwap(pair, request.DeroAddr, response.Deposit, &response) if err != nil { response.Error = err.Error() log.Println(err) } else { Delay.AddUser(request.DeroAddr) } response.Request = request return response } func newUpgrader() *websocket.Upgrader { u := websocket.NewUpgrader() u.CheckOrigin = (func(r *http.Request) bool { return true }) u.OnClose(func(c *websocket.Conn, err error) { WSConnections.Delete(c) }) u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) { var in, out WS_Message var send bytes.Buffer read := bytes.NewReader(data) decoder := json.NewDecoder(read) encoder := json.NewEncoder(&send) err := decoder.Decode(&in) if err != nil { fmt.Println(err) return } out.ID = in.ID switch in.Method { case "swap": var request coin.Swap_Request var response coin.Swap_Response p := in.Params.(map[string]any) request.Pair = p["pair"].(string) request.Amount = p["amount"].(float64) request.DeroAddr = p["dero_address"].(string) switch request.Pair { case coin.BTCDERO, coin.LTCDERO, coin.ARRRDERO, coin.XMRDERO: response = Dero_Swap(request) case coin.DEROBTC, coin.DEROLTC, coin.DEROARRR, coin.DEROXMR: response = Reverse_Swap(request) default: } out.Method = "swap" out.Result = response encoder.Encode(out) SendWSData(c, send.Bytes()) case "market": mk.RLock() defer mk.RUnlock() var data bytes.Buffer out.Method = "market" inner := mk.Pairs out.Result = inner encoder := json.NewEncoder(&data) encoder.Encode(out) SendWSData(c, data.Bytes()) case "balance": var data bytes.Buffer out.Method = "balance" out.Result = UpdatePool() encoder := json.NewEncoder(&data) encoder.Encode(out) SendWSData(c, data.Bytes()) default: } }) return u } func webSocketHandler(w http.ResponseWriter, r *http.Request) { upgrader := newUpgrader() conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } WSConnections.Store(conn, true) } func SendWSData(c *websocket.Conn, data []byte) { if len(data) == 0 { return } if c != nil { err := c.WriteMessage(websocket.TextMessage, data) if err != nil { log.Println(err) } } else { WSConnections.Range(func(k any, v any) bool { conn := k.(*websocket.Conn) err := conn.WriteMessage(websocket.TextMessage, data) if err != nil { log.Println(err) } return true }) } } func StartServer() { // cert files // Let's Encrypt: // certFile = fullchain.pem // keyFile = privkey.pem // uncomment the following block to enable TLS; edit cert files first /* cert, err := tls.LoadX509KeyPair("/etc/letsencrypt/live/mg25ot4aggt8dprv.myfritz.net/fullchain.pem", "/etc/letsencrypt/live/mg25ot4aggt8dprv.myfritz.net/privkey.pem") if err != nil { log.Println(err) os.Exit(2) } */ mux := http.NewServeMux() mux.HandleFunc("/ws", webSocketHandler) srv := nbhttp.NewServer(nbhttp.Config{ Network: "tcp", Handler: mux, // uncomment the following 2 lines and comment "Addrs" to start server with TLS //AddrsTLS: []string{cfg.Settings.ListenAddress}, //TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}}, Addrs: []string{cfg.Settings.ListenAddress}, }) err := srv.Start() if err != nil { log.Println(err) os.Exit(2) } srv.Wait() }