forked from heroiclabs/nakama
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcore_friend.go
143 lines (128 loc) · 4.08 KB
/
core_friend.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2017 The Nakama Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"database/sql"
"errors"
"encoding/json"
"fmt"
"go.uber.org/zap"
)
func friendAdd(logger *zap.Logger, db *sql.DB, ns *NotificationService, userID string, handle string, friendID string) error {
tx, txErr := db.Begin()
if txErr != nil {
return txErr
}
isFriendAccept := false
updatedAt := nowMs()
var err error
defer func() {
if err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil { // don't override value of err
logger.Error("Could not rollback transaction", zap.Error(rollbackErr))
}
} else {
if e := tx.Commit(); e != nil {
logger.Error("Could not commit transaction", zap.Error(e))
err = e
return
}
// If the operation was successful, send a notification.
content, e := json.Marshal(map[string]interface{}{"handle": handle})
if e != nil {
logger.Warn("Failed to send friend add notification", zap.Error(e))
return
}
var subject string
var code int64
if isFriendAccept {
subject = fmt.Sprintf("%v accepted your friend request", handle)
code = NOTIFICATION_FRIEND_ACCEPT
} else {
subject = fmt.Sprintf("%v wants to add you as a friend", handle)
code = NOTIFICATION_FRIEND_REQUEST
}
if e := ns.NotificationSend([]*NNotification{
&NNotification{
Id: generateNewId(),
UserID: friendID,
Subject: subject,
Content: content,
Code: code,
SenderID: userID,
CreatedAt: updatedAt,
ExpiresAt: updatedAt + ns.expiryMs,
Persistent: true,
},
}); e != nil {
logger.Warn("Failed to send friend add notification", zap.Error(e))
}
}
}()
// Mark an invite as accepted, if one was in place.
res, err := tx.Exec(`
UPDATE user_edge SET state = 0, updated_at = $3
WHERE (source_id = $1 AND destination_id = $2 AND state = 2)
OR (source_id = $2 AND destination_id = $1 AND state = 1)
`, friendID, userID, updatedAt)
if err != nil {
return err
}
// If both edges were updated, it was accepting an invite was successful.
if rowsAffected, _ := res.RowsAffected(); rowsAffected == 2 {
isFriendAccept = true
return err
}
// If no edge updates took place, it's a new invite being set up.
res, err = tx.Exec(`
INSERT INTO user_edge (source_id, destination_id, state, position, updated_at)
SELECT source_id, destination_id, state, position, updated_at
FROM (VALUES
($1::BYTEA, $2::BYTEA, 2, $3::BIGINT, $3::BIGINT),
($2::BYTEA, $1::BYTEA, 1, $3::BIGINT, $3::BIGINT)
) AS ue(source_id, destination_id, state, position, updated_at)
WHERE EXISTS (SELECT id FROM users WHERE id = $2::BYTEA)
`, userID, friendID, updatedAt)
if err != nil {
return err
}
// An invite was successfully added if both components were inserted.
if rowsAffected, _ := res.RowsAffected(); rowsAffected != 2 {
err = sql.ErrNoRows
return err
}
// Update the user edge metadata counts.
res, err = tx.Exec(`
UPDATE user_edge_metadata
SET count = count + 1, updated_at = $1
WHERE source_id = $2
OR source_id = $3`,
updatedAt, userID, friendID)
if err != nil {
return err
}
if rowsAffected, _ := res.RowsAffected(); rowsAffected != 2 {
err = errors.New("could not update user friend counts")
return err
}
return nil
}
func friendAddHandle(logger *zap.Logger, db *sql.DB, ns *NotificationService, userID string, handle string, friendHandle string) error {
var friendID string
err := db.QueryRow("SELECT id FROM users WHERE handle = $1", friendHandle).Scan(&friendID)
if err != nil {
return err
}
return friendAdd(logger, db, ns, userID, handle, friendID)
}