mirror of
https://github.com/originalmk/archat-server.git
synced 2024-11-20 09:38:50 +00:00
Finished basic connection initation
This commit is contained in:
parent
67eda0d069
commit
b23e8c00a6
@ -3,8 +3,9 @@ package client
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"golang.org/x/sync/errgroup"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
@ -13,11 +14,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"krzyzanowski.dev/archat/common"
|
||||||
cm "krzyzanowski.dev/archat/common"
|
cm "krzyzanowski.dev/archat/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type InitiationInfo struct {
|
||||||
|
otherSideNick string
|
||||||
|
}
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
// Assumption: size of 1 is enough, because first response read will be response for the last request
|
// Assumption: size of 1 is enough, because first response read will be response for the last request
|
||||||
@ -25,7 +33,7 @@ type Context struct {
|
|||||||
resFromServer chan cm.RFrame
|
resFromServer chan cm.RFrame
|
||||||
reqFromServer chan cm.RFrame
|
reqFromServer chan cm.RFrame
|
||||||
rToServer chan cm.RFrame
|
rToServer chan cm.RFrame
|
||||||
initiations []*cm.Initiation
|
initiations []InitiationInfo
|
||||||
initiationsLock sync.RWMutex
|
initiationsLock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +66,8 @@ handleNext:
|
|||||||
res, err = cliCtx.handleStartChatB(reqFrame)
|
res, err = cliCtx.handleStartChatB(reqFrame)
|
||||||
} else if reqFrame.ID == cm.StartChatDReqID {
|
} else if reqFrame.ID == cm.StartChatDReqID {
|
||||||
res, err = cliCtx.handleStartChatD(reqFrame)
|
res, err = cliCtx.handleStartChatD(reqFrame)
|
||||||
|
} else if reqFrame.ID == cm.StartChatFinishReqID {
|
||||||
|
res, err = cliCtx.handleChatStartFinish(reqFrame)
|
||||||
} else {
|
} else {
|
||||||
logger.Warn("can't handle it!")
|
logger.Warn("can't handle it!")
|
||||||
}
|
}
|
||||||
@ -103,10 +113,8 @@ func (cliCtx *Context) handleStartChatB(reqFrame cm.RFrame) (res cm.Response, er
|
|||||||
"decide if you want to accept the chat", startChatBReq.Nickname)
|
"decide if you want to accept the chat", startChatBReq.Nickname)
|
||||||
|
|
||||||
cliCtx.initiationsLock.Lock()
|
cliCtx.initiationsLock.Lock()
|
||||||
cliCtx.initiations = append(cliCtx.initiations, &cm.Initiation{
|
cliCtx.initiations = append(cliCtx.initiations, InitiationInfo{
|
||||||
AbANick: startChatBReq.Nickname,
|
otherSideNick: startChatBReq.Nickname,
|
||||||
AbBNick: "",
|
|
||||||
Stage: cm.InitiationStageB,
|
|
||||||
})
|
})
|
||||||
cliCtx.initiationsLock.Unlock()
|
cliCtx.initiationsLock.Unlock()
|
||||||
|
|
||||||
@ -126,16 +134,45 @@ func (cliCtx *Context) handleStartChatD(reqFrame cm.RFrame) (res cm.Response, er
|
|||||||
startChatDReq.Nickname, startChatDReq.PunchCode)
|
startChatDReq.Nickname, startChatDReq.PunchCode)
|
||||||
logger.Warn("handleStartChatD not implemented yet")
|
logger.Warn("handleStartChatD not implemented yet")
|
||||||
|
|
||||||
idx := slices.IndexFunc(cliCtx.initiations, func(i *cm.Initiation) bool {
|
idx := slices.IndexFunc(cliCtx.initiations, func(i InitiationInfo) bool {
|
||||||
return i.AbBNick == startChatDReq.Nickname
|
return i.otherSideNick == startChatDReq.Nickname
|
||||||
})
|
})
|
||||||
|
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
logger.Error("there is no initation related to chatstartd's nickname, ignoring")
|
logger.Error("there is no initation related to chatstartd's nickname, ignoring",
|
||||||
|
"nickname", startChatDReq.Nickname)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx.initiations[idx].Stage = cm.InitiationStageD
|
conn, err := net.Dial("udp", ":8081")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error udp dialing for punch", err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(conn)
|
||||||
|
err = enc.Encode(cm.PunchRequest{PunchCode: startChatDReq.PunchCode})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error sending punch request data", "err", err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("punch request sent!")
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) handleChatStartFinish(reqFrame common.RFrame) (res common.Response, err error) {
|
||||||
|
startChatFinishReq, err := common.RequestFromFrame[common.StartChatFinishRequest](reqFrame)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("got chat finish info!",
|
||||||
|
"nick", startChatFinishReq.OtherSideNickname,
|
||||||
|
"addr", startChatFinishReq.OtherSideAddress)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -288,8 +325,8 @@ func sendStartChatC(ctx *Context, nick string) {
|
|||||||
ctx.initiationsLock.Lock()
|
ctx.initiationsLock.Lock()
|
||||||
defer ctx.initiationsLock.Unlock()
|
defer ctx.initiationsLock.Unlock()
|
||||||
|
|
||||||
idx := slices.IndexFunc(ctx.initiations, func(i *cm.Initiation) bool {
|
idx := slices.IndexFunc(ctx.initiations, func(i InitiationInfo) bool {
|
||||||
return i.AbANick == nick
|
return i.otherSideNick == nick
|
||||||
})
|
})
|
||||||
|
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
@ -304,8 +341,6 @@ func sendStartChatC(ctx *Context, nick string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.initiations[idx].Stage = cm.InitiationStageC
|
|
||||||
|
|
||||||
logger.Debug("request sent, no wait for response")
|
logger.Debug("request sent, no wait for response")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,12 +434,18 @@ func RunClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendStartChatA(cliCtx, cmdArgs[0])
|
sendStartChatA(cliCtx, cmdArgs[0])
|
||||||
|
|
||||||
|
cliCtx.initiationsLock.Lock()
|
||||||
|
cliCtx.initiations = append(cliCtx.initiations, InitiationInfo{
|
||||||
|
otherSideNick: cmdArgs[0],
|
||||||
|
})
|
||||||
|
cliCtx.initiationsLock.Unlock()
|
||||||
} else if cmdName == "initations" {
|
} else if cmdName == "initations" {
|
||||||
logger.Info("displaying all initations...")
|
logger.Info("displaying all initations...")
|
||||||
|
|
||||||
cliCtx.initiationsLock.RLock()
|
cliCtx.initiationsLock.RLock()
|
||||||
for _, i := range cliCtx.initiations {
|
for _, i := range cliCtx.initiations {
|
||||||
logger.Debugf("from %s, stage: %d", i.AbANick, i.Stage)
|
logger.Debugf("with %s", i.otherSideNick)
|
||||||
}
|
}
|
||||||
cliCtx.initiationsLock.RUnlock()
|
cliCtx.initiationsLock.RUnlock()
|
||||||
} else if cmdName == "startchatc" {
|
} else if cmdName == "startchatc" {
|
||||||
|
@ -7,16 +7,17 @@ import (
|
|||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EchoReqID = 1
|
EchoReqID = 1
|
||||||
EchoResID = 128 + EchoReqID
|
EchoResID = 128 + EchoReqID
|
||||||
ListPeersReqID = 2
|
ListPeersReqID = 2
|
||||||
ListPeersResID = 128 + ListPeersReqID
|
ListPeersResID = 128 + ListPeersReqID
|
||||||
AuthReqID = 3
|
AuthReqID = 3
|
||||||
AuthResID = 128 + AuthReqID
|
AuthResID = 128 + AuthReqID
|
||||||
StartChatAReqID = 4
|
StartChatAReqID = 4
|
||||||
StartChatBReqID = 5
|
StartChatBReqID = 5
|
||||||
StartChatCReqID = 6
|
StartChatCReqID = 6
|
||||||
StartChatDReqID = 7
|
StartChatDReqID = 7
|
||||||
|
StartChatFinishReqID = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// Requests & responses subtypes
|
// Requests & responses subtypes
|
||||||
@ -181,12 +182,23 @@ func (StartChatDRequest) ID() int {
|
|||||||
return StartChatDReqID
|
return StartChatDReqID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StartChatFinishRequest struct {
|
||||||
|
OtherSideNickname string `json:"otherSideNickname"`
|
||||||
|
OtherSideAddress string `json:"otherSideAddress"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (StartChatFinishRequest) ID() int {
|
||||||
|
return StartChatFinishReqID
|
||||||
|
}
|
||||||
|
|
||||||
type Initiation struct {
|
type Initiation struct {
|
||||||
AbANick string
|
AbANick string
|
||||||
AbBNick string
|
AbBNick string
|
||||||
Stage int
|
Stage int
|
||||||
AbAPunchCode string
|
AbAPunchCode string
|
||||||
AbBPunchCode string
|
AbBPunchCode string
|
||||||
|
AbAAddress string
|
||||||
|
AbBAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -195,3 +207,11 @@ const (
|
|||||||
InitiationStageC = 3
|
InitiationStageC = 3
|
||||||
InitiationStageD = 4
|
InitiationStageD = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PunchRequest struct {
|
||||||
|
PunchCode string `json:"punchCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PunchResponse struct {
|
||||||
|
IPAddr int32 `json:"ipAddr"`
|
||||||
|
}
|
||||||
|
110
server/server.go
110
server/server.go
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
@ -614,6 +615,89 @@ func (ctx *Context) wsapiHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srvCtx *Context) handleUDP(data []byte, addr net.Addr) {
|
||||||
|
var punchReq common.PunchRequest
|
||||||
|
err := json.Unmarshal(data, &punchReq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error unmarshalling punch request", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debugf("got punch request %+v", punchReq)
|
||||||
|
|
||||||
|
srvCtx.initiationsLock.Lock()
|
||||||
|
defer srvCtx.initiationsLock.Unlock()
|
||||||
|
|
||||||
|
idx := slices.IndexFunc(srvCtx.initiations, func(i *common.Initiation) bool {
|
||||||
|
return i.AbAPunchCode == punchReq.PunchCode ||
|
||||||
|
i.AbBPunchCode == punchReq.PunchCode
|
||||||
|
})
|
||||||
|
|
||||||
|
if idx == -1 {
|
||||||
|
logger.Debugf("haven't found initiation for the request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
matchedInitation := srvCtx.initiations[idx]
|
||||||
|
logger.Debugf("matched initiation %+v", matchedInitation)
|
||||||
|
|
||||||
|
if matchedInitation.AbAPunchCode == punchReq.PunchCode {
|
||||||
|
matchedInitation.AbAAddress = addr.String()
|
||||||
|
} else {
|
||||||
|
matchedInitation.AbBAddress = addr.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchedInitation.AbAAddress == "" || matchedInitation.AbBAddress == "" {
|
||||||
|
// does not have two addresses can't do anything yet
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debugf("finished completing initiation %+v", matchedInitation)
|
||||||
|
logger.Debug("now sending peers their addresses")
|
||||||
|
|
||||||
|
srvCtx.peersListLock.Lock()
|
||||||
|
defer srvCtx.peersListLock.Unlock()
|
||||||
|
|
||||||
|
abA, err := srvCtx.getCtxByNick(matchedInitation.AbANick)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("could not finish punching, abA not found",
|
||||||
|
"err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
abB, err := srvCtx.getCtxByNick(matchedInitation.AbBNick)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("could not finish punching, abB not found",
|
||||||
|
"err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = abA.sendRequest(common.StartChatFinishRequest{
|
||||||
|
OtherSideNickname: matchedInitation.AbBNick,
|
||||||
|
OtherSideAddress: matchedInitation.AbBAddress,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("could not send start chat finish request to abA, aborting",
|
||||||
|
"err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = abB.sendRequest(common.StartChatFinishRequest{
|
||||||
|
OtherSideNickname: matchedInitation.AbANick,
|
||||||
|
OtherSideAddress: matchedInitation.AbAAddress,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("could not send start chat finish request to abB, aborting",
|
||||||
|
"err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func RunServer() {
|
func RunServer() {
|
||||||
srvCtx := NewContext()
|
srvCtx := NewContext()
|
||||||
|
|
||||||
@ -625,10 +709,30 @@ func RunServer() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
http.HandleFunc("/wsapi", srvCtx.wsapiHandler)
|
http.HandleFunc("/wsapi", srvCtx.wsapiHandler)
|
||||||
logger.Info("Starting server...")
|
logger.Info("Starting websocket server...")
|
||||||
err := http.ListenAndServe(":8080", nil)
|
go func() {
|
||||||
|
err := http.ListenAndServe(":8080", nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger.Info("Starting punching server...")
|
||||||
|
listener, err := net.ListenPacket("udp", ":8081")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error("could not create listener for punching server", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
data := make([]byte, 65536)
|
||||||
|
n, punchAddr, err := listener.ReadFrom(data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error reading from punching server", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data = data[:n]
|
||||||
|
logger.Debugf("got message: %+v", data)
|
||||||
|
srvCtx.handleUDP(data, punchAddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user