add client and groups member logic
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
# TODO — Code Logic Errors
|
||||
|
||||
## Critical
|
||||
|
||||
- [ ] **Login: nil pointer dereference** (`http.go:111`)
|
||||
`CacheGetClientByName` returns `nil` on miss, then `DbSetClientByName` is called with that nil `client` → panic. Should query DB by username directly.
|
||||
|
||||
- [ ] **Login: password never verified** (`http.go:87–131`)
|
||||
No call to `PasswordVerify`/`bcrypt.CompareHashAndPassword`. Anyone with a valid username can log in.
|
||||
|
||||
## High
|
||||
|
||||
- [ ] **Login: validates `username` length instead of `password`** (`http.go:98`)
|
||||
`if len(username) < 8` should be `if len(password) < 8`. Password is never length-checked.
|
||||
|
||||
- [ ] **DB: missing `&` in `Scan` for `pronouns`** (`database.go:87`)
|
||||
`client.Pronouns` should be `&client.Pronouns`. Compare with `DbSetClientById` which does it correctly.
|
||||
|
||||
- [ ] **WS: 30s context kills entire connection** (`wsServer.go:23`)
|
||||
A single 30s timeout context is shared across all reads in the loop. Should use per-read deadlines or `context.Background()` for the loop.
|
||||
|
||||
## Medium
|
||||
|
||||
- [ ] **NewUser: missing `return` after bad color error** (`http.go:54–56`)
|
||||
On `parseRgb` error, `http.Error` is called but execution continues with `color = [0,0,0]`.
|
||||
|
||||
- [ ] **WS: unauth disconnect deletes ID=0 from cache** (`wsServer.go:115`)
|
||||
`closeConnection` calls `CacheDeleteClient(client.Id)` but unauthenticated clients have `Id=0`, wiping whatever sits at key 0.
|
||||
|
||||
## Low
|
||||
|
||||
- [ ] **`CacheSetGroup` is a no-op** (`cache.go:59`)
|
||||
Function body is empty. The `Groups` cache is never populated, so every `CacheGetGroup` call misses and falls back to DB.
|
||||
@@ -42,7 +42,7 @@ func CacheGetClientByName(name string) (*Client, error) {
|
||||
return nil, fmt.Errorf("client %s not found", name)
|
||||
}
|
||||
|
||||
func CacheSetClient(client *Client) {
|
||||
func CacheSaveClient(client *Client) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
@@ -56,7 +56,12 @@ func CacheDeleteClient(id uint32) {
|
||||
delete(CacheClients, id)
|
||||
}
|
||||
|
||||
func CacheSetGroup() {}
|
||||
func CacheSaveGroup(group *Group) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
Groups[group.Id] = group
|
||||
}
|
||||
|
||||
func CacheGetGroup(id uint32) (*Group, error) {
|
||||
mu.RLock()
|
||||
|
||||
+67
-17
@@ -18,7 +18,7 @@ func DbInit(ctx context.Context) {
|
||||
}
|
||||
|
||||
_, err = dbConn.Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS client (
|
||||
CREATE TABLE IF NOT EXISTS clients (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(20) UNIQUE NOT NULL,
|
||||
pass_hash VARCHAR(60) NOT NULL,
|
||||
@@ -37,8 +37,8 @@ func DbInit(ctx context.Context) {
|
||||
CREATE TABLE IF NOT EXISTS chat_groups (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(48) NOT NULL,
|
||||
creator_id INTEGER NOT NULL REFERENCES client(id) ON DELETE CASCADE,
|
||||
owner_id INTEGER NOT NULL REFERENCES client(id) ON DELETE CASCADE,
|
||||
creator_id INTEGER NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
||||
owner_id INTEGER NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
||||
enable_client_colors BOOLEAN NOT NULL DEFAULT true,
|
||||
color_red SMALLINT DEFAULT NULL,
|
||||
color_green SMALLINT DEFAULT NULL,
|
||||
@@ -53,7 +53,7 @@ func DbInit(ctx context.Context) {
|
||||
_, err = dbConn.Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS chat_group_members (
|
||||
group_id INTEGER NOT NULL REFERENCES chat_groups(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES client(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
||||
joined_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (group_id, user_id)
|
||||
)
|
||||
@@ -73,22 +73,17 @@ func DbSaveClientWithoutGroups(ctx context.Context, client *Client) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func DbGetIdByClientName(ctx context.Context, name string) (uint32, error) {
|
||||
var id uint32
|
||||
err := dbConn.QueryRow(ctx, `
|
||||
SELECT id FROM clients WHERE name = $1
|
||||
`, name).Scan(&id)
|
||||
return id, err
|
||||
}
|
||||
|
||||
func DbSetClientByName(ctx context.Context, client *Client) error {
|
||||
err := dbConn.QueryRow(ctx, `
|
||||
SELECT name, pass_hash, color_red, color_green, color_blue, created_at FROM clients WHERE name = $1
|
||||
`, client.Name).Scan(&client.Name, &client.PasswordHash, &client.Pronouns, &client.Color[0], &client.Color[1], &client.Color[2], &client.CreatedAt)
|
||||
return err
|
||||
SELECT id, name, pass_hash, pronouns, color_red, color_green, color_blue, created_at FROM clients WHERE name = $1
|
||||
`, client.Name).Scan(&client.Id, &client.Name, &client.PasswordHash, &client.Pronouns, &client.Color[0], &client.Color[1], &client.Color[2], &client.CreatedAt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return DbSetClientGroups(ctx, client)
|
||||
}
|
||||
|
||||
func DbSetClientById(ctx context.Context, client *Client) error {
|
||||
func DbSetClientByIdWithoutGroups(ctx context.Context, client *Client) error {
|
||||
err := dbConn.QueryRow(ctx, `
|
||||
SELECT name, pass_hash, pronouns, color_red, color_green, color_blue, created_at FROM clients WHERE id = $1
|
||||
`, client.Id).Scan(&client.Name, &client.PasswordHash, &client.Pronouns, &client.Color[0], &client.Color[1], &client.Color[2], &client.CreatedAt)
|
||||
@@ -102,10 +97,17 @@ func DbSaveGroupWithoutClients(ctx context.Context, group *Group) error {
|
||||
RETURNING id
|
||||
`, group.Name, group.CreatorId, group.OwnerId, group.EnableClientColors, group.Color[0], group.Color[1], group.Color[2], group.CreatedAt).
|
||||
Scan(&group.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = dbConn.Exec(ctx, `
|
||||
INSERT INTO chat_group_members (group_id, user_id, joined_at)
|
||||
VALUES ($1, $2, $3)
|
||||
`, group.Id, group.OwnerId, group.CreatedAt)
|
||||
return err
|
||||
}
|
||||
|
||||
func DbSetGroupById(ctx context.Context, group *Group) error {
|
||||
func DbSetGroupByIdWithoutClients(ctx context.Context, group *Group) error {
|
||||
err := dbConn.QueryRow(ctx, `
|
||||
SELECT name, creator_id, owner_id, enable_client_colors, color_red, color_green, color_blue, created_at FROM chat_groups WHERE id = $1
|
||||
`, group.Id).Scan(&group.Name, &group.CreatorId, &group.OwnerId, &group.EnableClientColors, &group.Color[0], &group.Color[1], &group.Color[2], &group.CreatedAt)
|
||||
@@ -132,6 +134,34 @@ func DbSetGroupById(ctx context.Context, group *Group) error {
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func DbSetGroupById(ctx context.Context, group *Group) error {
|
||||
err := DbSetGroupByIdWithoutClients(ctx, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return DbSetGroupMemberClients(ctx, group)
|
||||
}
|
||||
|
||||
func DbSetGroupMemberClients(ctx context.Context, group *Group) error {
|
||||
rows, err := dbConn.Query(ctx, `
|
||||
SELECT user_id FROM chat_group_members WHERE group_id = $1
|
||||
`, group.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
group.Clients = make(map[uint32]struct{})
|
||||
for rows.Next() {
|
||||
var userId uint32
|
||||
if err := rows.Scan(&userId); err != nil {
|
||||
return err
|
||||
}
|
||||
group.Clients[userId] = struct{}{}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func DbAddClientsToGroup(ctx context.Context, groupId uint32, clientIds []uint32) error {
|
||||
batch := &pgx.Batch{}
|
||||
now := time.Now()
|
||||
@@ -151,3 +181,23 @@ func DbAddClientsToGroup(ctx context.Context, groupId uint32, clientIds []uint32
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DbSetClientGroups(ctx context.Context, client *Client) error {
|
||||
rows, err := dbConn.Query(ctx, `
|
||||
SELECT group_id FROM chat_group_members WHERE user_id = $1
|
||||
`, client.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
client.Groups = make(map[uint32]struct{})
|
||||
for rows.Next() {
|
||||
var groupId uint32
|
||||
if err := rows.Scan(&groupId); err != nil {
|
||||
return err
|
||||
}
|
||||
client.Groups[groupId] = struct{}{}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
@@ -117,15 +117,15 @@ func HttpHandleLogin(response http.ResponseWriter, request *http.Request) {
|
||||
|
||||
err := DbSetClientByName(ctx, client)
|
||||
if err != nil {
|
||||
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||
http.Error(response, "bad login1", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
CacheSetClient(client)
|
||||
CacheSaveClient(client)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(client.PasswordHash), []byte(password))
|
||||
if err != nil {
|
||||
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||
http.Error(response, "bad login2", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func HttpHandleGroupCreate(response http.ResponseWriter, request *http.Request)
|
||||
if err == nil {
|
||||
client = *cacheClient
|
||||
} else {
|
||||
err = DbSetClientById(ctx, &client)
|
||||
err = DbSetClientByIdWithoutGroups(ctx, &client)
|
||||
if err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
@@ -191,6 +191,7 @@ func HttpHandleGroupCreate(response http.ResponseWriter, request *http.Request)
|
||||
OwnerId: clientId,
|
||||
CreatorId: clientId,
|
||||
Color: color,
|
||||
Clients: map[uint32]struct{}{clientId: {}},
|
||||
}
|
||||
|
||||
enableClientColors := request.FormValue("enableClientColors")
|
||||
@@ -200,14 +201,14 @@ func HttpHandleGroupCreate(response http.ResponseWriter, request *http.Request)
|
||||
|
||||
err = DbSaveGroupWithoutClients(ctx, &group)
|
||||
if err != nil {
|
||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||
http.Error(response, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
groupIdBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(groupIdBytes, group.Id)
|
||||
|
||||
response.WriteHeader(http.StatusCreated)
|
||||
response.Write([]byte(groupIdBytes))
|
||||
response.Write(groupIdBytes)
|
||||
}
|
||||
|
||||
func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Request) {
|
||||
@@ -236,7 +237,7 @@ func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Reques
|
||||
if err == nil {
|
||||
group = *groupPtr
|
||||
} else {
|
||||
err = DbSetGroupById(ctx, &group)
|
||||
err = DbSetGroupByIdWithoutClients(ctx, &group)
|
||||
if err != nil {
|
||||
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||
return
|
||||
|
||||
@@ -72,13 +72,14 @@
|
||||
<button class="tab-btn active" onclick="switchTab('login')">Login</button>
|
||||
<button class="tab-btn" onclick="switchTab('register')">Register</button>
|
||||
<button class="tab-btn" onclick="switchTab('connect')">Connect</button>
|
||||
<button class="tab-btn" onclick="switchTab('group')">Group</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-login" class="tab active">
|
||||
<label>Username</label>
|
||||
<input id="login-username" type="text" placeholder="alice">
|
||||
<label style="margin-top:10px;">Password</label>
|
||||
<input id="login-password" type="password" placeholder="••••••••">
|
||||
<input id="login-password" type="text" placeholder="password">
|
||||
<button onclick="login()">Login</button>
|
||||
</div>
|
||||
|
||||
@@ -86,7 +87,7 @@
|
||||
<label>Username</label>
|
||||
<input id="reg-username" type="text" placeholder="alice">
|
||||
<label style="margin-top:10px;">Password</label>
|
||||
<input id="reg-password" type="password" placeholder="••••••••">
|
||||
<input id="reg-password" type="text" placeholder="password">
|
||||
<label style="margin-top:10px;">Color (r,g,b)</label>
|
||||
<input id="reg-color" type="text" placeholder="255,100,50">
|
||||
<button onclick="register()">Register</button>
|
||||
@@ -100,6 +101,18 @@
|
||||
<button id="connect-btn" onclick="connect()">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-group" class="tab">
|
||||
<label>Token</label>
|
||||
<input id="group-token" type="text" placeholder="Paste token from login">
|
||||
<label style="margin-top:10px;">Name (optional)</label>
|
||||
<input id="group-name" type="text" placeholder="Best group ever">
|
||||
<label style="margin-top:10px;">Color (r,g,b or red/green/blue)</label>
|
||||
<input id="group-color" type="text" placeholder="255,100,50">
|
||||
<label style="margin-top:10px;">Enable client colors</label>
|
||||
<input id="group-client-colors" type="text" placeholder="1 or 0">
|
||||
<button onclick="createGroup()">Create Group</button>
|
||||
</div>
|
||||
|
||||
<div id="form-status"></div>
|
||||
<div id="status">Not connected</div>
|
||||
</div>
|
||||
@@ -141,7 +154,7 @@
|
||||
|
||||
const body = new URLSearchParams({ username, password, color });
|
||||
try {
|
||||
const res = await fetch('http://localhost:8080/newuser', { method: 'POST', body });
|
||||
const res = await fetch('http://localhost:8080/new/client', { method: 'POST', body });
|
||||
const text = await res.text();
|
||||
if (res.ok) {
|
||||
setFormStatus('Registered! Now login.', 'ok');
|
||||
@@ -160,11 +173,12 @@
|
||||
|
||||
const body = new URLSearchParams({ username, password });
|
||||
try {
|
||||
const res = await fetch('http://localhost:8080/login', { method: 'POST', body });
|
||||
const res = await fetch('http://localhost:8080/new/token', { method: 'POST', body });
|
||||
const text = await res.text();
|
||||
if (res.ok) {
|
||||
document.getElementById('username-input').value = username;
|
||||
document.getElementById('token-input').value = text;
|
||||
document.getElementById('group-token').value = text;
|
||||
setFormStatus('Logged in! Token copied to Connect tab.', 'ok');
|
||||
switchTab('connect');
|
||||
} else {
|
||||
@@ -175,6 +189,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function createGroup() {
|
||||
const token = document.getElementById('group-token').value.trim();
|
||||
if (!token) { setFormStatus('Paste a token first', 'err'); return; }
|
||||
|
||||
const body = new URLSearchParams({ token });
|
||||
const name = document.getElementById('group-name').value.trim();
|
||||
if (name) body.set('name', name);
|
||||
const color = document.getElementById('group-color').value.trim();
|
||||
if (color) body.set('color', color);
|
||||
const enableClientColors = document.getElementById('group-client-colors').value.trim();
|
||||
if (enableClientColors) body.set('enableClientColors', enableClientColors);
|
||||
|
||||
try {
|
||||
const res = await fetch('http://localhost:8080/new/group', { method: 'POST', body });
|
||||
if (res.ok) {
|
||||
const buf = await res.arrayBuffer();
|
||||
const id = new DataView(buf).getUint32(0, false);
|
||||
setFormStatus('Group created! ID: ' + id, 'ok');
|
||||
} else {
|
||||
setFormStatus('Error: ' + await res.text(), 'err');
|
||||
}
|
||||
} catch (e) {
|
||||
setFormStatus('Request failed: ' + e.message, 'err');
|
||||
}
|
||||
}
|
||||
|
||||
function setStatus(text, cls) {
|
||||
const el = document.getElementById('status');
|
||||
el.textContent = text;
|
||||
|
||||
@@ -6,14 +6,21 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func withCORS(h http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
h(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
DbInit(ctx)
|
||||
|
||||
http.HandleFunc("/newuser", HttpHandleNewUser)
|
||||
http.HandleFunc("/login", HttpHandleLogin)
|
||||
http.HandleFunc("/group/create", HttpHandleGroupCreate)
|
||||
http.HandleFunc("/group/addclient", HttpHandleGroupAddClient)
|
||||
http.HandleFunc("/new/client", withCORS(HttpHandleNewUser))
|
||||
http.HandleFunc("/new/token", withCORS(HttpHandleLogin))
|
||||
http.HandleFunc("/new/group", withCORS(HttpHandleGroupCreate))
|
||||
http.HandleFunc("/mod/group/addclients", withCORS(HttpHandleGroupAddClient))
|
||||
http.HandleFunc("/ws", ServeWsConnection)
|
||||
|
||||
log.Println("listening on :8080")
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
crash on adding to group
|
||||
|
||||
2026/03/27 18:44:04 listening on :8080
|
||||
2026/03/27 18:45:17 read error: failed to read JSON message: failed to get reader: received close frame: status = StatusNoStatusRcvd and reason = ""
|
||||
2026/03/27 18:45:17 http: panic serving 127.0.0.1:54644: runtime error: invalid memory address or nil pointer dereference
|
||||
goroutine 25 [running]:
|
||||
net/http.(*conn).serve.func1()
|
||||
/usr/lib/go/src/net/http/server.go:1907 +0xbd
|
||||
panic({0x8e0f20?, 0xe2b190?})
|
||||
/usr/lib/go/src/runtime/panic.go:860 +0x13a
|
||||
github.com/coder/websocket.(*Conn).casClosing(...)
|
||||
/home/ffus/go/pkg/mod/github.com/coder/websocket@v1.8.14/close.go:325
|
||||
github.com/coder/websocket.(*Conn).CloseNow(0x2d8e00000002?)
|
||||
/home/ffus/go/pkg/mod/github.com/coder/websocket@v1.8.14/close.go:135 +0x48
|
||||
main.closeConnection(0x2d8ef7ddd990?, 0xb8?)
|
||||
/home/ffus/Projects/go-socket/wsServer.go:183 +0x2d
|
||||
main.ServeWsConnection({0x9c4a68?, 0x2d8ef7ee41e0?}, 0x2d8ef7d5db30?)
|
||||
/home/ffus/Projects/go-socket/wsServer.go:36 +0x350
|
||||
net/http.HandlerFunc.ServeHTTP(0xe43400?, {0x9c4a68?, 0x2d8ef7ee41e0?}, 0x7e1176?)
|
||||
/usr/lib/go/src/net/http/server.go:2286 +0x29
|
||||
net/http.(*ServeMux).ServeHTTP(0x482d39?, {0x9c4a68, 0x2d8ef7ee41e0}, 0x2d8ef7de4a00)
|
||||
/usr/lib/go/src/net/http/server.go:2828 +0x1c7
|
||||
net/http.serverHandler.ServeHTTP({0x2d8ef7d748c0?}, {0x9c4a68?, 0x2d8ef7ee41e0?}, 0x6?)
|
||||
/usr/lib/go/src/net/http/server.go:3311 +0x8e
|
||||
net/http.(*conn).serve(0x2d8ef7df8360, {0x9c5e48, 0x2d8ef7e1c570})
|
||||
/usr/lib/go/src/net/http/server.go:2073 +0x650
|
||||
created by net/http.(*Server).Serve in goroutine 1
|
||||
/usr/lib/go/src/net/http/server.go:3464 +0x485
|
||||
2026/03/27 18:47:47 read error: failed to read JSON message: failed to get reader: received close frame: status = StatusNoStatusRcvd and reason = ""
|
||||
2026/03/27 18:47:47 http: panic serving 127.0.0.1:54648: runtime error: invalid memory address or nil pointer dereference
|
||||
goroutine 53 [running]:
|
||||
net/http.(*conn).serve.func1()
|
||||
/usr/lib/go/src/net/http/server.go:1907 +0xbd
|
||||
panic({0x8e0f20?, 0xe2b190?})
|
||||
/usr/lib/go/src/runtime/panic.go:860 +0x13a
|
||||
github.com/coder/websocket.(*Conn).casClosing(...)
|
||||
/home/ffus/go/pkg/mod/github.com/coder/websocket@v1.8.14/close.go:325
|
||||
github.com/coder/websocket.(*Conn).CloseNow(0x2d8e00000001?)
|
||||
/home/ffus/go/pkg/mod/github.com/coder/websocket@v1.8.14/close.go:135 +0x48
|
||||
main.closeConnection(0x2d8ef7f61990?, 0xb8?)
|
||||
/home/ffus/Projects/go-socket/wsServer.go:183 +0x2d
|
||||
main.ServeWsConnection({0x9c4a68?, 0x2d8ef7f2c1e0?}, 0x2d8ef7f56b30?)
|
||||
/home/ffus/Projects/go-socket/wsServer.go:36 +0x350
|
||||
net/http.HandlerFunc.ServeHTTP(0xe43400?, {0x9c4a68?, 0x2d8ef7f2c1e0?}, 0x7e1176?)
|
||||
/usr/lib/go/src/net/http/server.go:2286 +0x29
|
||||
net/http.(*ServeMux).ServeHTTP(0x482d39?, {0x9c4a68, 0x2d8ef7f2c1e0}, 0x2d8ef7f26140)
|
||||
/usr/lib/go/src/net/http/server.go:2828 +0x1c7
|
||||
net/http.serverHandler.ServeHTTP({0x2d8ef7f38080?}, {0x9c4a68?, 0x2d8ef7f2c1e0?}, 0x6?)
|
||||
/usr/lib/go/src/net/http/server.go:3311 +0x8e
|
||||
net/http.(*conn).serve(0x2d8ef7f2a2d0, {0x9c5e48, 0x2d8ef7e1c570})
|
||||
/usr/lib/go/src/net/http/server.go:2073 +0x650
|
||||
created by net/http.(*Server).Serve in goroutine 1
|
||||
/usr/lib/go/src/net/http/server.go:3464 +0x485
|
||||
+66
-3
@@ -42,7 +42,7 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !handleUnauthenticatedMessage(&client, &clientMessage) {
|
||||
if !handleUnauthenticatedMessage(ctx, &client, &clientMessage) {
|
||||
ignoreCache = true
|
||||
return
|
||||
}
|
||||
@@ -53,6 +53,10 @@ func ServeWsConnection(responseWriter http.ResponseWriter, request *http.Request
|
||||
}
|
||||
|
||||
func sendMessageCloseIfTimeout(client *Client, message *map[string]any) {
|
||||
if client.WsConn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
@@ -74,11 +78,52 @@ func sendToAllMessageCloseIfTimeout(message *map[string]any) {
|
||||
}
|
||||
|
||||
func handleAuthenticatedMessage(client *Client, clientMessage *map[string]any) bool {
|
||||
sendToAllMessageCloseIfTimeout(clientMessage)
|
||||
subject, ok := (*clientMessage)["subject"].(uint32)
|
||||
if !ok {
|
||||
var msg = map[string]any{
|
||||
"from": "server",
|
||||
"error": "subject invalid",
|
||||
}
|
||||
sendMessageCloseIfTimeout(client, &msg)
|
||||
}
|
||||
|
||||
content, ok := (*clientMessage)["content"].(string)
|
||||
if !ok {
|
||||
var msg = map[string]any{
|
||||
"from": "server",
|
||||
"error": "content invalid",
|
||||
}
|
||||
sendMessageCloseIfTimeout(client, &msg)
|
||||
}
|
||||
|
||||
group, err := CacheGetGroup(subject)
|
||||
if err != nil {
|
||||
var msg = map[string]any{
|
||||
"from": "server",
|
||||
"error": "subject invalid",
|
||||
}
|
||||
sendMessageCloseIfTimeout(client, &msg)
|
||||
}
|
||||
|
||||
for groupClientId, _ := range group.Clients {
|
||||
var msg = map[string]any{
|
||||
"from": "group",
|
||||
"group": group.Id,
|
||||
"sender": client.Name,
|
||||
"content": content,
|
||||
}
|
||||
|
||||
var groupClient *Client
|
||||
groupClient, err = CacheGetClientById(groupClientId)
|
||||
if err != nil {
|
||||
sendMessageCloseIfTimeout(groupClient, &msg)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func handleUnauthenticatedMessage(client *Client, clientMessage *map[string]any) bool {
|
||||
func handleUnauthenticatedMessage(ctx context.Context, client *Client, clientMessage *map[string]any) bool {
|
||||
token, ok := (*clientMessage)["token"].(string)
|
||||
if !ok {
|
||||
var msg = map[string]any{
|
||||
@@ -110,6 +155,24 @@ func handleUnauthenticatedMessage(client *Client, clientMessage *map[string]any)
|
||||
}
|
||||
|
||||
*client = *clientFromCache
|
||||
|
||||
for groupId, _ := range clientFromCache.Groups {
|
||||
_, err = CacheGetGroup(groupId)
|
||||
if err != nil {
|
||||
dbGroup := &Group{Id: groupId}
|
||||
|
||||
err = DbSetGroupById(ctx, dbGroup)
|
||||
if err != nil {
|
||||
var msg = map[string]any{
|
||||
"from": "server",
|
||||
"error": "invalid client data",
|
||||
}
|
||||
sendMessageCloseIfTimeout(client, &msg)
|
||||
return false
|
||||
}
|
||||
CacheSaveGroup(dbGroup)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user