MAJOR: ADDED SQLITE MSG PERSISTENCE
This commit is contained in:
parent
44da1e17a6
commit
0898143876
148
main.go
148
main.go
@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ergochat/irc-go/ircmsg"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
@ -71,6 +73,7 @@ var (
|
||||
cliMu sync.RWMutex // mutex for clients
|
||||
motdString []string
|
||||
motdFile string
|
||||
db *sql.DB
|
||||
)
|
||||
|
||||
func loadConfig() (*Config, error) {
|
||||
@ -123,6 +126,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("Error listening: %v\n", err)
|
||||
}
|
||||
sqlinitDB()
|
||||
log.Printf("IRC server listening on port %d\n", cfg.Port)
|
||||
go startHTTP(*cfg)
|
||||
for {
|
||||
@ -450,18 +454,20 @@ func (c *Client) serveHistory(subcmd, target string, count int, params []string)
|
||||
c.fwrite(":server 461 %s CHATHISTORY :Not enough parameters\r\n", c.nick)
|
||||
return
|
||||
}
|
||||
msgid := params[2] // format: msgid=12345
|
||||
msgid = strings.TrimPrefix(msgid, "msgid=")
|
||||
idx := findMsgIndex(ch.history, msgid)
|
||||
if idx == -1 {
|
||||
msgid := strings.TrimPrefix(params[2], "msgid=")
|
||||
|
||||
rows, err := db.Query(`SELECT msgid, timestamp, prefix, command, msg
|
||||
FROM messages
|
||||
WHERE channel=? AND msgid < ?
|
||||
ORDER BY timestamp DESC LIMIT ?`,
|
||||
target, msgid, count)
|
||||
if err != nil {
|
||||
c.fwrite(":server 718 %s %s :No history available\r\n", c.nick, target)
|
||||
return
|
||||
}
|
||||
start := idx - count
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
msgs = ch.history[start:idx]
|
||||
defer rows.Close()
|
||||
|
||||
msgs = scanRows(rows, target)
|
||||
|
||||
case "AFTER":
|
||||
if len(params) < 4 {
|
||||
@ -469,16 +475,19 @@ func (c *Client) serveHistory(subcmd, target string, count int, params []string)
|
||||
return
|
||||
}
|
||||
msgid := strings.TrimPrefix(params[2], "msgid=")
|
||||
idx := findMsgIndex(ch.history, msgid)
|
||||
if idx == -1 {
|
||||
|
||||
rows, err := db.Query(`SELECT msgid, timestamp, prefix, command, msg
|
||||
FROM messages
|
||||
WHERE channel=? AND msgid > ?
|
||||
ORDER BY timestamp ASC LIMIT ?`,
|
||||
target, msgid, count)
|
||||
if err != nil {
|
||||
c.fwrite(":server 718 %s %s :No history available\r\n", c.nick, target)
|
||||
return
|
||||
}
|
||||
end := idx + 1 + count
|
||||
if end > len(ch.history) {
|
||||
end = len(ch.history)
|
||||
}
|
||||
msgs = ch.history[idx+1 : end]
|
||||
defer rows.Close()
|
||||
|
||||
msgs = scanRows(rows, target)
|
||||
|
||||
case "AROUND":
|
||||
if len(params) < 4 {
|
||||
@ -486,21 +495,27 @@ func (c *Client) serveHistory(subcmd, target string, count int, params []string)
|
||||
return
|
||||
}
|
||||
msgid := strings.TrimPrefix(params[2], "msgid=")
|
||||
idx := findMsgIndex(ch.history, msgid)
|
||||
if idx == -1 {
|
||||
c.fwrite(":server 718 %s %s :No history available\r\n", c.nick, target)
|
||||
return
|
||||
}
|
||||
half := count / 2
|
||||
start := idx - half
|
||||
if start < 0 {
|
||||
start = 0
|
||||
beforeRows, _ := db.Query(`SELECT msgid, timestamp, prefix, command, msg
|
||||
FROM messages
|
||||
WHERE channel=? AND msgid < ?
|
||||
ORDER BY timestamp DESC LIMIT ?`,
|
||||
target, msgid, half)
|
||||
beforeMsgs := scanRows(beforeRows, target)
|
||||
anchor, err := findMsgIndex(target, msgid)
|
||||
var anchorMsg []HistoryMessage
|
||||
if err == nil && anchor != nil {
|
||||
anchorMsg = []HistoryMessage{*anchor}
|
||||
}
|
||||
end := idx + half + 1
|
||||
if end > len(ch.history) {
|
||||
end = len(ch.history)
|
||||
}
|
||||
msgs = ch.history[start:end]
|
||||
afterRows, _ := db.Query(`SELECT msgid, timestamp, prefix, command, msg
|
||||
FROM messages
|
||||
WHERE channel=? AND msgid > ?
|
||||
ORDER BY timestamp ASC LIMIT ?`,
|
||||
target, msgid, half)
|
||||
afterMsgs := scanRows(afterRows, target)
|
||||
|
||||
msgs = append(beforeMsgs, anchorMsg...)
|
||||
msgs = append(msgs, afterMsgs...)
|
||||
}
|
||||
batchID := fmt.Sprintf("hist-%d", time.Now().UnixNano())
|
||||
c.fwrite(":server BATCH +%s chathistory %s\r\n", batchID, target)
|
||||
@ -519,13 +534,20 @@ func (c *Client) serveHistory(subcmd, target string, count int, params []string)
|
||||
|
||||
c.fwrite(":server BATCH -%s\r\n", batchID)
|
||||
}
|
||||
func findMsgIndex(history []HistoryMessage, msgid string) int {
|
||||
for i, m := range history {
|
||||
if m.MsgID == msgid {
|
||||
return i
|
||||
}
|
||||
func findMsgIndex(channel, msgid string) (*HistoryMessage, error) {
|
||||
row := db.QueryRow(`SELECT msgid, timestamp, prefix, command, msg
|
||||
FROM messages
|
||||
WHERE channel=? AND msgid=?`, channel, msgid)
|
||||
|
||||
var m HistoryMessage
|
||||
var ts string
|
||||
err := row.Scan(&m.MsgID, &ts, &m.Prefix, &m.Command, &m.Text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return -1
|
||||
m.Time, _ = time.Parse(time.RFC3339, ts)
|
||||
m.Params = []string{channel}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func kickUser(sender *Client, channelName, targetNick, reason string) {
|
||||
@ -686,6 +708,7 @@ func sendMessage(sender *Client, target, text string) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ch.mu.RLock()
|
||||
_, member := ch.members[sender.nick]
|
||||
ch.mu.RUnlock()
|
||||
if !member {
|
||||
@ -795,6 +818,19 @@ func storeMessage(ch *Channel, sender *Client, target, text string) {
|
||||
if len(ch.history) > 1000 {
|
||||
ch.history = ch.history[1:] // drop oldest
|
||||
}
|
||||
_, err := db.Exec(`INSERT INTO messages(msgid, nick, timestamp, channel, prefix, command, msg)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?)`,
|
||||
msg.MsgID,
|
||||
sender.nick,
|
||||
msg.Time.UTC().Format(time.RFC3339),
|
||||
target,
|
||||
msg.Prefix,
|
||||
msg.Command,
|
||||
msg.Text,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("storeMessage error: %v", err)
|
||||
}
|
||||
}
|
||||
func nicknameExists(nick string) bool {
|
||||
cliMu.RLock()
|
||||
@ -890,3 +926,45 @@ func checkCredentials(user, pass string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// database stuff
|
||||
func sqlinitDB() error {
|
||||
var err error
|
||||
db, err = sql.Open("sqlite3", "irc.db")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
msg := HistoryMessage{
|
||||
MsgID: fmt.Sprintf("%d", time.Now().UnixNano()),
|
||||
Time: time.Now(),
|
||||
Prefix: fmt.Sprintf("%s!%s@%s", sender.nick, sender.user, sender.host),
|
||||
Command: "PRIVMSG",
|
||||
Params: []string{target},
|
||||
Text: text,
|
||||
}
|
||||
*/
|
||||
stmt := `CREATE TABLE IF NOT EXISTS messages(
|
||||
msgid TEXT PRIMARY KEY,
|
||||
nick TEXT,
|
||||
timestamp TEXT,
|
||||
channel TEXT,
|
||||
prefix TEXT,
|
||||
command TEXT,
|
||||
msg TEXT
|
||||
)`
|
||||
_, err = db.Exec(stmt)
|
||||
return err
|
||||
}
|
||||
func scanRows(rows *sql.Rows, channel string) []HistoryMessage {
|
||||
var msgs []HistoryMessage
|
||||
for rows.Next() {
|
||||
var m HistoryMessage
|
||||
var ts string
|
||||
rows.Scan(&m.MsgID, &ts, &m.Prefix, &m.Command, &m.Text)
|
||||
m.Time, _ = time.Parse(time.RFC3339, ts)
|
||||
m.Params = []string{channel}
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user