Browse Source

Added message "memorisation"

master
Gitea 2 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 => { socket.onmessage = event => {
let message = JSON.parse(event.data); let message = JSON.parse(event.data);
let from_user = message.from.username; let from_user = message.from.username;
let date = new Date(message.timestamp).toLocaleString();
let constructed_message_to_display = `${from_user}: ${message.contents}` + "\n"; let constructed_message_to_display = `[${date}] ${from_user}: ${message.contents}` + "\n";
let chatbox = document.getElementById("chatbox"); let chatbox = document.getElementById("chatbox");
chatbox.innerHTML += constructed_message_to_display; chatbox.innerHTML += constructed_message_to_display;

35
src/api/db.go

@ -25,8 +25,8 @@ import (
) )
const ( const (
UsersTablename string = "users" UsersTablename string = "users"
// MessagesTablename string = "messages" MessagesTablename string = "messages"
) )
// SQL database wrapper // SQL database wrapper
@ -51,21 +51,21 @@ func (db *DB) createUsersTable() error {
return nil return nil
} }
// func (db *DB) createMessagesTable() error { func (db *DB) createMessagesTable() error {
// command := fmt.Sprintf( command := fmt.Sprintf(
// `CREATE TABLE IF NOT EXISTS %s `CREATE TABLE IF NOT EXISTS %s
// (id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL, (id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL,
// from_name TEXT NOT NULL, FOREIGN KEY(from_name) REFERENCES %s(username))`, sender TEXT NOT NULL, timestamp INTEGER, FOREIGN KEY(sender) REFERENCES %s(username))`,
// MessagesTablename, UsersTablename, MessagesTablename, UsersTablename,
// ) )
// _, err := db.Exec(command) _, err := db.Exec(command)
// if err != nil { if err != nil {
// return err return err
// } }
// return nil return nil
// } }
func (db *DB) setUpTables() error { func (db *DB) setUpTables() error {
err := db.createUsersTable() err := db.createUsersTable()
@ -73,6 +73,11 @@ func (db *DB) setUpTables() error {
return fmt.Errorf("error creating users table: %s", err) 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 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 package api
import (
"fmt"
"strconv"
)
// A message struct that is converted back and forth to JSON in order to communicate with frontend // A message struct that is converted back and forth to JSON in order to communicate with frontend
type Message struct { type Message struct {
ID uint64
TimeStamp uint64 `json:"timestamp"` TimeStamp uint64 `json:"timestamp"`
From User `json:"from"` From User `json:"from"`
Contents string `json:"contents"` Contents string `json:"contents"`
} }
/* PROBABLY come back later and implement a message-remembering feature */ // 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 { func (db *DB) AddMessage(message Message) error {
// command := fmt.Sprintf("INSERT INTO %s(from, contents) VALUES(%s, %s)", MessagesTablename, message.From.Name, message.Contents) // check how many messages are already stored
// _, err := db.Exec(command) command := fmt.Sprintf("SELECT COUNT(*) FROM %s", MessagesTablename)
// if err != nil { result := db.QueryRow(command)
// return err err := result.Err()
// } if err != nil {
return err
// return nil }
// }
var countStr string
// func (db *DB) GetAllMessages() (*[]Message, error) { result.Scan(&countStr)
// command := fmt.Sprintf("SELECT * FROM %s", MessagesTablename) count, err := strconv.ParseUint(countStr, 10, 64)
// rows, err := db.Query(command) if err != nil {
// if err != nil { return err
// return nil, err }
// }
if count >= uint64(MaxMessagesRemembered) {
// var messages []Message // remove the last one
command = fmt.Sprintf("DELETE FROM %s WHERE timestamp = (SELECT MIN(timestamp) FROM %s)", MessagesTablename, MessagesTablename)
// /* _, err := db.Exec(command)
// (id INTEGER NOT NULL PRIMARY KEY, content TEXT NOT NULL, if err != nil {
// to_name TEXT NOT NULL, from_name TEXT NOT NULL, FOREIGN KEY(from_name, to_name) REFERENCES %s(username, username))`, return err
// */ }
// for rows.Next() { }
// var message Message
// rows.Scan(&message.ID, &message.Contents, message.From.Name) command = fmt.Sprintf("INSERT INTO %s(sender, content, timestamp) VALUES(\"%s\", \"%s\", %d)", MessagesTablename, message.From.Name, message.Contents, message.TimeStamp)
// messages = append(messages, message) _, err = db.Exec(command)
// } if err != nil {
return err
// return &messages, nil }
// }
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 ( import (
"fmt" "fmt"
"unbewohnte.xyz/gochat/log"
) )
const HashLength uint = 64 const HashLength uint = 64
@ -63,8 +61,6 @@ func (db *DB) CreateUser(user *User) error {
return err return err
} }
log.Info("created user \"%s\"", user.Name)
return nil return nil
} }

3
src/api/websocket.go

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

2
src/log/log.go

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

26
src/server/websocketHandler.go

@ -19,6 +19,7 @@ package server
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"time"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"unbewohnte.xyz/gochat/api" "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 // add this new authorized socket to the broadcast
s.websockets.Sockets = append(s.websockets.Sockets, &newWS) 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) 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{ newConnectionMessage := api.Message{
From: api.UserSystem, From: api.UserSystem,
Contents: fmt.Sprintf("%s has connected", newWS.User.Name), Contents: fmt.Sprintf("%s has connected", newWS.User.Name),
@ -82,6 +95,17 @@ func (s *Server) BroadcastMessages() {
break 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 { for _, ws := range s.websockets.Sockets {
ws.Socket.WriteJSON(&message) ws.Socket.WriteJSON(&message)
} }

Loading…
Cancel
Save