You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.4 KiB
Go
177 lines
4.4 KiB
Go
package chat
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const DefaultCacheLength = 20
|
|
|
|
type Server struct {
|
|
clients map[string]*Client
|
|
messageCache List
|
|
Name string `json:"name"`
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
type Message struct {
|
|
Text string `json:"text"`
|
|
Time int64 `json:"time"`
|
|
User string `json:"user"`
|
|
ServerId string `json:"serverId"`
|
|
}
|
|
|
|
var Servers map[string]*Server
|
|
|
|
func StartServer(name string) (s Server) {
|
|
s = Server{make(map[string]*Client), newList(DefaultCacheLength), name, sync.WaitGroup{}}
|
|
Servers[name] = &s
|
|
s.putServer()
|
|
s.loadInitMessages()
|
|
return
|
|
}
|
|
|
|
func getServer(name string) (*Server, error) {
|
|
if name == "" {
|
|
name = "root"
|
|
}
|
|
if s, ok := Servers[name]; ok {
|
|
return s, nil
|
|
}
|
|
|
|
_, exists := retrieveServerFromDb(name)
|
|
if !exists {
|
|
return nil, fmt.Errorf("server does not exist")
|
|
}
|
|
|
|
server := StartServer(name)
|
|
return &server, nil
|
|
}
|
|
|
|
func retrieveServerFromDb(name string) (s *Server, found bool) {
|
|
res, err := http.Get(DbAddress + "/server?name=" + name)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "could not reach db server", err)
|
|
return
|
|
}
|
|
if res.StatusCode != http.StatusOK {
|
|
fmt.Println("server", name, "not found on db")
|
|
return
|
|
}
|
|
if err := json.NewDecoder(res.Body).Decode(&s); err != nil {
|
|
fmt.Fprintln(os.Stderr, "error retrieving server details from db", err)
|
|
return
|
|
}
|
|
return s, true
|
|
}
|
|
|
|
func (s *Server) reportClients() (count int) {
|
|
for range s.clients {
|
|
count++
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *Server) sendMessage(message string) {
|
|
mess := Message{message, time.Now().UnixMilli(), s.Name, ""}
|
|
wm := WrappedMessage{"server", mess}
|
|
for _, client := range s.clients {
|
|
client.receivedMessages <- wm
|
|
}
|
|
}
|
|
|
|
func (s *Server) broadcastMessage(mess *Message) {
|
|
wm := WrappedMessage{"", *mess}
|
|
for _, client := range s.clients {
|
|
client.receivedMessages <- wm
|
|
}
|
|
}
|
|
|
|
func (s *Server) storeMessage(mess *Message) {
|
|
s.messageCache.add(&ListNode{nil, *mess})
|
|
s.wg.Done()
|
|
jsonData, ok := encodeJson(mess)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if res, err := http.Post(DbAddress+"/message?name="+s.Name, "application/json", bytes.NewBuffer(jsonData)); err != nil {
|
|
fmt.Fprintln(os.Stderr, "db server post error", err.Error())
|
|
} else {
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "error reading response body:", err)
|
|
}
|
|
if res.StatusCode != http.StatusOK {
|
|
fmt.Println("could not store message", string(body))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Server) loadInitMessages() {
|
|
status, _, messages := s.loadMessages(0, DefaultCacheLength)
|
|
if status != http.StatusOK {
|
|
fmt.Fprintln(os.Stderr, "Could not load initial messages from db")
|
|
return
|
|
}
|
|
s.messageCache.fromMessageSlice(messages)
|
|
}
|
|
|
|
func (s *Server) loadMessages(offset, count int) (status int, message string, messages []Message) {
|
|
if res, err := http.Get(DbAddress + "/message?name=" + s.Name + "&offset=" + strconv.Itoa(offset) + "&count=" + strconv.Itoa(count)); err != nil {
|
|
fmt.Fprintln(os.Stderr, "db server get messages error", err.Error())
|
|
} else {
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "error reading response body:", err)
|
|
}
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
fmt.Println("load messages error", string(body))
|
|
return res.StatusCode, string(body), nil
|
|
} else {
|
|
messages = make([]Message, 0)
|
|
if err := json.Unmarshal(body, &messages); err != nil {
|
|
fmt.Fprintln(os.Stderr, "Error unmarshalling messages from db", err.Error())
|
|
return http.StatusInternalServerError, "Error unmarshalling messages from db " + err.Error(), nil
|
|
}
|
|
}
|
|
}
|
|
return http.StatusOK, "", messages
|
|
}
|
|
|
|
func (s *Server) putServer() {
|
|
jsonData, ok := encodeJson(&s)
|
|
if !ok {
|
|
fmt.Fprintln(os.Stderr, "error encoding server")
|
|
return
|
|
}
|
|
res, err := http.Post(DbAddress+"/server", "application/json", bytes.NewBuffer(jsonData))
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "POST server to db error:", err.Error())
|
|
return
|
|
}
|
|
if res.StatusCode == http.StatusOK {
|
|
fmt.Println("server", s.Name, "already in db")
|
|
var temp Server
|
|
if err := json.NewDecoder(res.Body).Decode(&temp); err != nil {
|
|
fmt.Println("error updating local server details with those from db")
|
|
return
|
|
}
|
|
//TODO: update details which get pulled from db rather than on creation
|
|
return
|
|
}
|
|
if res.StatusCode == http.StatusCreated {
|
|
fmt.Println("server", s.Name, "added to db")
|
|
return
|
|
}
|
|
|
|
}
|