dero-swaps/server.go

278 lines
5.6 KiB
Go
Raw Normal View History

2024-04-11 13:35:17 +01:00
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
/*
2024-04-11 13:35:17 +01:00
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)
}
*/
2024-04-11 13:35:17 +01:00
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},
2024-04-11 13:35:17 +01:00
})
2024-04-11 20:37:31 +01:00
err := srv.Start()
2024-04-11 13:35:17 +01:00
if err != nil {
log.Println(err)
os.Exit(2)
}
srv.Wait()
}