Browse Source

Added message "memorisation"

master
Gitea 3 years ago
parent
commit
b61fc7fe76
  1. 4
      scripts/chat.js
  2. 35
      src/api/db.go
  3. 7
      src/api/limits.go
  4. 92
      src/api/message.go
  5. 4
      src/api/user.go
  6. 3
      src/api/websocket.go
  7. 2
      src/log/log.go
  8. 26
      src/server/websocketHandler.go

4
scripts/chat.js

@ -48,8 +48,8 @@ areCredentialsValid({username:username, secret_hash:secret_hash})
socket.onmessage = event => {
let message = JSON.parse(event.data);
let from_user = message.from.username;
let constructed_message_to_display = `${from_user}: ${message.contents}` + "\n";
let date = new Date(message.timestamp).toLocaleString();
let constructed_message_to_display = `[${date}] ${from_user}: ${message.contents}` + "\n";
let chatbox = document.getElementById("chatbox");
chatbox.innerHTML += constructed_message_to_display;

35
src/api/db.go

@ -25,8 +25,8 @@ import (
)
const (
UsersTablename string = "users"
// MessagesTablename string = "messages"
UsersTablename string = "users"
MessagesTablename string = "messages"
)
// SQL database wrapper
@ -51,21 +51,21 @@ func (db *DB) createUsersTable() error {
return nil
}
// func (db *DB) createMessagesTable() error {
// command := fmt.Sprintf(
// `CREATE TABLE IF NOT EXISTS %s
// (id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL,
// from_name TEXT NOT NULL, FOREIGN KEY(from_name) REFERENCES %s(username))`,
// MessagesTablename, UsersTablename,
// )
func (db *DB) createMessagesTable() error {
command := fmt.Sprintf(
`CREATE TABLE IF NOT EXISTS %s
(id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL,
sender TEXT NOT NULL, timestamp INTEGER, FOREIGN KEY(sender) REFERENCES %s(username))`,
MessagesTablename, UsersTablename,
)
// _, err := db.Exec(command)
// if err != nil {
// return err
// }
_, err := db.Exec(command)
if err != nil {
return err
}
// return nil
// }
return nil
}
func (db *DB) setUpTables() error {
err := db.createUsersTable()
@ -73,6 +73,11 @@ func (db *DB) setUpTables() error {
return fmt.Errorf("error creating users table: %s", err)
}
err = db.createMessagesTable()
if err != nil {
return fmt.Errorf("error creating messages table: %s", err)
}
return nil
}

7
src/api/limits.go

@ -0,0 +1,7 @@
package api
// How many characters can message hold
const MaxMessageContentLen uint = 500
// How many messages can be "remembered" until removal
const MaxMessagesRemembered uint = 50

92
src/api/message.go

@ -16,43 +16,69 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
package api
import (
"fmt"
"strconv"
)
// A message struct that is converted back and forth to JSON in order to communicate with frontend
type Message struct {
ID uint64
TimeStamp uint64 `json:"timestamp"`
From User `json:"from"`
Contents string `json:"contents"`
}
/* PROBABLY come back later and implement a message-remembering feature */
// func (db *DB) AddMessage(message Message) error {
// command := fmt.Sprintf("INSERT INTO %s(from, contents) VALUES(%s, %s)", MessagesTablename, message.From.Name, message.Contents)
// _, err := db.Exec(command)
// if err != nil {
// return err
// }
// return nil
// }
// func (db *DB) GetAllMessages() (*[]Message, error) {
// command := fmt.Sprintf("SELECT * FROM %s", MessagesTablename)
// rows, err := db.Query(command)
// if err != nil {
// return nil, err
// }
// var messages []Message
// /*
// (id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL,
// to_name TEXT NOT NULL, from_name TEXT NOT NULL, FOREIGN KEY(from_name, to_name) REFERENCES %s(username, username))`,
// */
// for rows.Next() {
// var message Message
// rows.Scan(&message.ID, &message.Contents, message.From.Name)
// messages = append(messages, message)
// }
// return &messages, nil
// }
// Add a new message to the database, following the limitations and removing the
// oldest one as well if the capacity has been exceeded
func (db *DB) AddMessage(message Message) error {
// check how many messages are already stored
command := fmt.Sprintf("SELECT COUNT(*) FROM %s", MessagesTablename)
result := db.QueryRow(command)
err := result.Err()
if err != nil {
return err
}
var countStr string
result.Scan(&countStr)
count, err := strconv.ParseUint(countStr, 10, 64)
if err != nil {
return err
}
if count >= uint64(MaxMessagesRemembered) {
// remove the last one
command = fmt.Sprintf("DELETE FROM %s WHERE timestamp = (SELECT MIN(timestamp) FROM %s)", MessagesTablename, MessagesTablename)
_, err := db.Exec(command)
if err != nil {
return err
}
}
command = fmt.Sprintf("INSERT INTO %s(sender, content, timestamp) VALUES(\"%s\", \"%s\", %d)", MessagesTablename, message.From.Name, message.Contents, message.TimeStamp)
_, err = db.Exec(command)
if err != nil {
return err
}
return nil
}
func (db *DB) GetAllMessages() (*[]Message, error) {
command := fmt.Sprintf("SELECT * FROM %s", MessagesTablename)
rows, err := db.Query(command)
if err != nil {
return nil, err
}
var messages []Message
for rows.Next() {
var message Message
rows.Scan(&message.ID, &message.Contents, &message.From.Name, &message.TimeStamp)
messages = append(messages, message)
}
return &messages, nil
}

4
src/api/user.go

@ -18,8 +18,6 @@ package api
import (
"fmt"
"unbewohnte.xyz/gochat/log"
)
const HashLength uint = 64
@ -63,8 +61,6 @@ func (db *DB) CreateUser(user *User) error {
return err
}
log.Info("created user \"%s\"", user.Name)
return nil
}

3
src/api/websocket.go

@ -95,11 +95,12 @@ func (holder *WSHolder) HandleNewWebSocketMessages(ws *WS, output chan Message)
break
}
if len(newMessage.Contents) < 1 {
if len(newMessage.Contents) < 1 || uint(len(newMessage.Contents)) > MaxMessageContentLen {
break
}
newMessage.From = ws.User
newMessage.TimeStamp = uint64(time.Now().UnixMilli())
output <- newMessage
}

2
src/log/log.go

@ -32,7 +32,7 @@ var (
func init() {
infoLog = log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime)
warningLog = log.New(os.Stdout, "[WARNING] ", log.Ldate|log.Ltime)
errorLog = log.New(os.Stdout, "[ERROR] ", log.Ldate|log.Ltime|log.Lshortfile)
errorLog = log.New(os.Stdout, "[ERROR] ", log.Ldate|log.Ltime)
}
// Set up loggers to write to the given writer

26
src/server/websocketHandler.go

@ -19,6 +19,7 @@ package server
import (
"fmt"
"net/http"
"time"
"github.com/gorilla/websocket"
"unbewohnte.xyz/gochat/api"
@ -64,9 +65,21 @@ func (s *Server) HandlerWebsockets(w http.ResponseWriter, req *http.Request) {
// add this new authorized socket to the broadcast
s.websockets.Sockets = append(s.websockets.Sockets, &newWS)
log.Info("A new websocket connection has been established with %s as \"%s\"", newWS.Socket.RemoteAddr(), newWS.User.Name)
log.Info("a new websocket connection has been established with %s as \"%s\"", newWS.Socket.RemoteAddr(), newWS.User.Name)
go s.websockets.HandleNewWebSocketMessages(&newWS, s.incomingMessages)
// send this new socket all previous messages to display
allMessages, err := s.db.GetAllMessages()
if err != nil {
// well, or not
log.Error("could not get all previous messages to display for %s: %s", newWS.User.Name, err)
} else {
for _, message := range *allMessages {
newWS.Socket.WriteJSON(&message)
}
}
// notify chat that a new user has connected
newConnectionMessage := api.Message{
From: api.UserSystem,
Contents: fmt.Sprintf("%s has connected", newWS.User.Name),
@ -82,6 +95,17 @@ func (s *Server) BroadcastMessages() {
break
}
if message.From.Name == api.UserSystem.Name {
// add timestapm manually for the system user
message.TimeStamp = uint64(time.Now().Unix())
}
// add incoming message to the db
err := s.db.AddMessage(message)
if err != nil {
log.Error("could not add a new message from %s to the db: %s", message.From.Name, err)
}
for _, ws := range s.websockets.Sockets {
ws.Socket.WriteJSON(&message)
}

Loading…
Cancel
Save