514 lines
12 KiB
Go
514 lines
12 KiB
Go
/*
|
|
Package babble is the active record implementation for global chat messages in the game.
|
|
|
|
Babble represents the global chat system where players can communicate with each other in real-time. The package provides comprehensive chat message management with features like mentions, search, time-based queries, and moderation utilities.
|
|
|
|
# Basic Usage
|
|
|
|
To retrieve a babble message by ID:
|
|
|
|
message, err := babble.Find(db, 1)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("<%s> %s\n", message.Author, message.Babble)
|
|
|
|
To get all babble messages:
|
|
|
|
allMessages, err := babble.All(db)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for _, message := range allMessages {
|
|
fmt.Printf("[%s] <%s> %s\n",
|
|
message.PostedTime().Format("15:04"),
|
|
message.Author,
|
|
message.Babble)
|
|
}
|
|
|
|
To get recent chat messages:
|
|
|
|
recentChat, err := babble.Recent(db, 50)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
To filter messages by author:
|
|
|
|
userMessages, err := babble.ByAuthor(db, "PlayerName")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
# Creating Messages with Builder Pattern
|
|
|
|
The package provides a fluent builder interface for creating new chat messages:
|
|
|
|
message, err := babble.NewBuilder(db).
|
|
WithAuthor("PlayerName").
|
|
WithBabble("Hello everyone! Ready for some adventure?").
|
|
WithPostedTime(time.Now()).
|
|
Create()
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Posted message with ID: %d\n", message.ID)
|
|
|
|
The builder automatically sets the current time if no posted time is specified:
|
|
|
|
message, err := babble.NewBuilder(db).
|
|
WithAuthor("Admin").
|
|
WithMessage("Server restart in 5 minutes!").
|
|
Create() // Uses current timestamp
|
|
|
|
You can use either `WithBabble()` or `WithMessage()` - they are aliases for the same functionality.
|
|
|
|
# Updating Messages
|
|
|
|
Chat messages can be modified and saved back to the database:
|
|
|
|
message, _ := babble.Find(db, 1)
|
|
message.Babble = "[EDITED] Original message was inappropriate"
|
|
|
|
err := message.Save()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
# Deleting Messages
|
|
|
|
Messages can be removed from the database (for moderation):
|
|
|
|
message, _ := babble.Find(db, 1)
|
|
err := message.Delete()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
# Database Schema
|
|
|
|
The babble table has the following structure:
|
|
|
|
CREATE TABLE babble (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
posted INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
author TEXT NOT NULL DEFAULT '',
|
|
babble TEXT NOT NULL DEFAULT ''
|
|
)
|
|
|
|
Where:
|
|
- id: Unique identifier for the chat message
|
|
- posted: Unix timestamp when the message was posted
|
|
- author: Username of the player who posted the message
|
|
- babble: The text content of the chat message
|
|
|
|
# Time-Based Queries
|
|
|
|
## Recent Messages
|
|
|
|
Get the most recent chat messages:
|
|
|
|
// Get 100 most recent messages for chat display
|
|
chatHistory, err := babble.Recent(db, 100)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Println("=== Recent Chat ===")
|
|
for _, msg := range chatHistory {
|
|
age := msg.Age()
|
|
timeStr := ""
|
|
if age < time.Minute {
|
|
timeStr = "just now"
|
|
} else if age < time.Hour {
|
|
timeStr = fmt.Sprintf("%dm ago", int(age.Minutes()))
|
|
} else {
|
|
timeStr = msg.PostedTime().Format("15:04")
|
|
}
|
|
|
|
fmt.Printf("[%s] <%s> %s\n", timeStr, msg.Author, msg.Babble)
|
|
}
|
|
|
|
## Messages Since Timestamp
|
|
|
|
Get messages posted since a specific time:
|
|
|
|
// Get messages since user's last login
|
|
lastLogin := getUserLastLogin(userID)
|
|
newMessages, err := babble.Since(db, lastLogin)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if len(newMessages) > 0 {
|
|
fmt.Printf("You missed %d messages while you were away\n", len(newMessages))
|
|
}
|
|
|
|
## Messages Between Timestamps
|
|
|
|
Get messages within a time range:
|
|
|
|
// Get today's chat history
|
|
startOfDay := time.Now().Truncate(24 * time.Hour).Unix()
|
|
endOfDay := time.Now().Unix()
|
|
|
|
todaysChat, err := babble.Between(db, startOfDay, endOfDay)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
# Search and Filtering
|
|
|
|
## Text Search
|
|
|
|
Search for messages containing specific terms:
|
|
|
|
// Search for messages about "boss fight"
|
|
bossMessages, err := babble.Search(db, "boss fight")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for _, msg := range bossMessages {
|
|
fmt.Printf("<%s> %s\n", msg.Author, msg.Preview(60))
|
|
}
|
|
|
|
Search is case-insensitive and matches partial words.
|
|
|
|
## Author-Based Queries
|
|
|
|
Get messages from specific players:
|
|
|
|
// Get recent messages from a player
|
|
playerRecent, err := babble.RecentByAuthor(db, "PlayerName", 10)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Get all messages from a player (for moderation)
|
|
allPlayerMessages, err := babble.ByAuthor(db, "ReportedPlayer")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
All author searches are case-insensitive.
|
|
|
|
# Mention System
|
|
|
|
## Finding Mentions
|
|
|
|
The package includes a comprehensive mention system using @username syntax:
|
|
|
|
message, _ := babble.Find(db, someID)
|
|
|
|
// Get all mentioned usernames
|
|
mentions := message.GetMentions()
|
|
for _, username := range mentions {
|
|
fmt.Printf("Message mentions: @%s\n", username)
|
|
}
|
|
|
|
// Check if specific user is mentioned
|
|
if message.HasMention("PlayerName") {
|
|
fmt.Println("You were mentioned in this message!")
|
|
}
|
|
|
|
## Mention Parsing
|
|
|
|
The mention system handles various formats:
|
|
- `@username` - Basic mention
|
|
- `@username!` - With punctuation
|
|
- `@username,` - In lists
|
|
- `@username?` - In questions
|
|
|
|
Mentions are extracted without the punctuation and are case-insensitive.
|
|
|
|
## Notification Integration
|
|
|
|
Use mentions for player notifications:
|
|
|
|
// Process new messages for mentions
|
|
recentMessages, _ := babble.Recent(db, 50)
|
|
|
|
for _, msg := range recentMessages {
|
|
mentions := msg.GetMentions()
|
|
for _, mentionedUser := range mentions {
|
|
// Send notification to mentioned user
|
|
notifyUser(mentionedUser, fmt.Sprintf("%s mentioned you: %s",
|
|
msg.Author, msg.Preview(50)))
|
|
}
|
|
}
|
|
|
|
# Message Analysis
|
|
|
|
## Content Analysis
|
|
|
|
Analyze message content for moderation or statistics:
|
|
|
|
message, _ := babble.Find(db, someID)
|
|
|
|
// Basic content metrics
|
|
fmt.Printf("Length: %d characters\n", message.Length())
|
|
fmt.Printf("Words: %d\n", message.WordCount())
|
|
|
|
// Content checks
|
|
if message.IsEmpty() {
|
|
fmt.Println("Empty message detected")
|
|
}
|
|
|
|
if message.IsLongMessage(200) {
|
|
fmt.Println("Very long message - possible spam")
|
|
}
|
|
|
|
// Search within message
|
|
if message.Contains("inappropriate_term") {
|
|
fmt.Println("Message flagged for review")
|
|
}
|
|
|
|
## Time Analysis
|
|
|
|
Analyze posting patterns:
|
|
|
|
message, _ := babble.Find(db, someID)
|
|
|
|
age := message.Age()
|
|
fmt.Printf("Message posted %v ago\n", age)
|
|
|
|
if message.IsRecent() {
|
|
fmt.Println("This is a recent message (within 1 hour)")
|
|
}
|
|
|
|
// Format for display
|
|
postedTime := message.PostedTime()
|
|
if age < 24*time.Hour {
|
|
fmt.Printf("Posted at %s\n", postedTime.Format("15:04"))
|
|
} else {
|
|
fmt.Printf("Posted on %s\n", postedTime.Format("Jan 2 15:04"))
|
|
}
|
|
|
|
# Chat Display Patterns
|
|
|
|
## Live Chat Feed
|
|
|
|
Display real-time chat messages:
|
|
|
|
func displayChatFeed(db *database.DB) {
|
|
messages, _ := babble.Recent(db, 50)
|
|
|
|
fmt.Println("=== Global Chat ===")
|
|
for i := len(messages) - 1; i >= 0; i-- { // Reverse for chronological order
|
|
msg := messages[i]
|
|
|
|
// Format timestamp
|
|
age := msg.Age()
|
|
var timeStr string
|
|
if age < time.Minute {
|
|
timeStr = "now"
|
|
} else if age < time.Hour {
|
|
timeStr = fmt.Sprintf("%dm", int(age.Minutes()))
|
|
} else {
|
|
timeStr = msg.PostedTime().Format("15:04")
|
|
}
|
|
|
|
// Handle mentions highlighting
|
|
content := msg.Babble
|
|
if msg.HasMention(currentUser) {
|
|
content = fmt.Sprintf("🔔 %s", content) // Highlight mentions
|
|
}
|
|
|
|
fmt.Printf("[%s] <%s> %s\n", timeStr, msg.Author, content)
|
|
}
|
|
}
|
|
|
|
## Chat History Browser
|
|
|
|
Browse historical messages:
|
|
|
|
func browseChatHistory(db *database.DB, page int, pageSize int) {
|
|
offset := page * pageSize
|
|
|
|
// Get paginated results (implement with LIMIT/OFFSET)
|
|
allMessages, _ := babble.All(db)
|
|
|
|
start := offset
|
|
end := offset + pageSize
|
|
if end > len(allMessages) {
|
|
end = len(allMessages)
|
|
}
|
|
|
|
if start >= len(allMessages) {
|
|
fmt.Println("No more messages")
|
|
return
|
|
}
|
|
|
|
pageMessages := allMessages[start:end]
|
|
|
|
fmt.Printf("=== Chat History (Page %d) ===\n", page+1)
|
|
for _, msg := range pageMessages {
|
|
fmt.Printf("%s <%s> %s\n",
|
|
msg.PostedTime().Format("Jan 2 15:04"),
|
|
msg.Author,
|
|
msg.Babble)
|
|
}
|
|
}
|
|
|
|
# Moderation Features
|
|
|
|
## Content Moderation
|
|
|
|
Tools for chat moderation:
|
|
|
|
// Flag inappropriate messages
|
|
func moderateMessage(db *database.DB, messageID int) {
|
|
msg, err := babble.Find(db, messageID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Check for spam (very short or very long)
|
|
if msg.WordCount() < 2 {
|
|
fmt.Printf("Possible spam: %s\n", msg.Preview(30))
|
|
}
|
|
|
|
if msg.IsLongMessage(500) {
|
|
fmt.Printf("Very long message from %s\n", msg.Author)
|
|
}
|
|
|
|
// Check for excessive mentions
|
|
mentions := msg.GetMentions()
|
|
if len(mentions) > 5 {
|
|
fmt.Printf("Message with %d mentions from %s\n", len(mentions), msg.Author)
|
|
}
|
|
}
|
|
|
|
## User Activity Analysis
|
|
|
|
Analyze user posting patterns:
|
|
|
|
// Check user activity
|
|
func analyzeUserActivity(db *database.DB, username string) {
|
|
// Recent activity
|
|
recentMessages, _ := babble.RecentByAuthor(db, username, 10)
|
|
|
|
fmt.Printf("User %s recent activity:\n", username)
|
|
fmt.Printf("- Recent messages: %d\n", len(recentMessages))
|
|
|
|
if len(recentMessages) > 0 {
|
|
totalWords := 0
|
|
for _, msg := range recentMessages {
|
|
totalWords += msg.WordCount()
|
|
}
|
|
avgWords := totalWords / len(recentMessages)
|
|
fmt.Printf("- Average words per message: %d\n", avgWords)
|
|
|
|
latest := recentMessages[0]
|
|
fmt.Printf("- Last message: %s (%s ago)\n",
|
|
latest.Preview(40), latest.Age())
|
|
}
|
|
|
|
// Check for mention patterns
|
|
allUserMessages, _ := babble.ByAuthor(db, username)
|
|
mentionCount := 0
|
|
for _, msg := range allUserMessages {
|
|
mentionCount += len(msg.GetMentions())
|
|
}
|
|
|
|
if len(allUserMessages) > 0 {
|
|
avgMentions := float64(mentionCount) / float64(len(allUserMessages))
|
|
fmt.Printf("- Average mentions per message: %.2f\n", avgMentions)
|
|
}
|
|
}
|
|
|
|
# Performance Considerations
|
|
|
|
## Efficient Queries
|
|
|
|
All time-based queries are optimized:
|
|
|
|
// Recent messages are efficiently ordered
|
|
recent, _ := babble.Recent(db, 100) // Uses LIMIT for efficiency
|
|
|
|
// Time-based queries use indexed timestamp
|
|
since, _ := babble.Since(db, timestamp) // Efficient with proper index
|
|
|
|
// Author queries support case-insensitive search
|
|
authorMessages, _ := babble.ByAuthor(db, "username") // Uses LOWER() function
|
|
|
|
## Memory Management
|
|
|
|
For large chat histories, process in batches:
|
|
|
|
// Process messages in batches
|
|
func processAllMessages(db *database.DB, batchSize int) {
|
|
allMessages, _ := babble.All(db)
|
|
|
|
for i := 0; i < len(allMessages); i += batchSize {
|
|
end := i + batchSize
|
|
if end > len(allMessages) {
|
|
end = len(allMessages)
|
|
}
|
|
|
|
batch := allMessages[i:end]
|
|
processBatch(batch)
|
|
}
|
|
}
|
|
|
|
# Integration Examples
|
|
|
|
## Real-Time Chat
|
|
|
|
Implement live chat updates:
|
|
|
|
func pollForNewMessages(db *database.DB, lastMessageID int) []*babble.Babble {
|
|
// Get messages newer than last seen
|
|
allMessages, _ := babble.All(db)
|
|
|
|
newMessages := make([]*babble.Babble, 0)
|
|
for _, msg := range allMessages {
|
|
if msg.ID > lastMessageID {
|
|
newMessages = append(newMessages, msg)
|
|
}
|
|
}
|
|
|
|
return newMessages
|
|
}
|
|
|
|
## Chat Commands
|
|
|
|
Process special chat commands:
|
|
|
|
func processMessage(db *database.DB, author, content string) {
|
|
// Check for commands
|
|
if strings.HasPrefix(content, "/") {
|
|
handleCommand(author, content)
|
|
return
|
|
}
|
|
|
|
// Regular chat message
|
|
msg, err := babble.NewBuilder(db).
|
|
WithAuthor(author).
|
|
WithBabble(content).
|
|
Create()
|
|
|
|
if err != nil {
|
|
log.Printf("Failed to save message: %v", err)
|
|
return
|
|
}
|
|
|
|
// Process mentions for notifications
|
|
mentions := msg.GetMentions()
|
|
for _, username := range mentions {
|
|
sendMentionNotification(username, msg)
|
|
}
|
|
}
|
|
|
|
# Error Handling
|
|
|
|
All functions return appropriate errors for common failure cases:
|
|
- Message not found (Find returns error for non-existent IDs)
|
|
- Database connection issues
|
|
- Invalid operations (e.g., saving/deleting messages without IDs)
|
|
- Search query errors
|
|
- Time range validation errors
|
|
*/
|
|
package babble |