Handle kick, rename server to network

This commit is contained in:
Ken-Håvard Lieng 2020-06-15 10:58:51 +02:00
parent a33157ff84
commit 6985dd16da
65 changed files with 2650 additions and 2179 deletions

View file

@ -48,8 +48,8 @@ func (b *Bleve) Index(id string, message *storage.Message) error {
return b.index.Index(id, message)
}
func (b *Bleve) SearchMessages(server, channel, q string) ([]string, error) {
serverQuery := bleve.NewMatchQuery(server)
func (b *Bleve) SearchMessages(network, channel, q string) ([]string, error) {
serverQuery := bleve.NewMatchQuery(network)
serverQuery.SetField("server")
channelQuery := bleve.NewMatchQuery(channel)
channelQuery.SetField("to")

View file

@ -13,7 +13,7 @@ import (
var (
bucketUsers = []byte("Users")
bucketServers = []byte("Servers")
bucketNetworks = []byte("Networks")
bucketChannels = []byte("Channels")
bucketOpenDMs = []byte("OpenDMs")
bucketMessages = []byte("Messages")
@ -33,7 +33,7 @@ func New(path string) (*BoltStore, error) {
db.Update(func(tx *bolt.Tx) error {
tx.CreateBucketIfNotExists(bucketUsers)
tx.CreateBucketIfNotExists(bucketServers)
tx.CreateBucketIfNotExists(bucketNetworks)
tx.CreateBucketIfNotExists(bucketChannels)
tx.CreateBucketIfNotExists(bucketOpenDMs)
tx.CreateBucketIfNotExists(bucketMessages)
@ -50,7 +50,7 @@ func (s *BoltStore) Close() {
s.db.Close()
}
func (s *BoltStore) GetUsers() ([]*storage.User, error) {
func (s *BoltStore) Users() ([]*storage.User, error) {
var users []*storage.User
s.db.View(func(tx *bolt.Tx) error {
@ -99,69 +99,69 @@ func (s *BoltStore) DeleteUser(user *storage.User) error {
}
return deletePrefix(user.IDBytes,
tx.Bucket(bucketServers),
tx.Bucket(bucketNetworks),
tx.Bucket(bucketChannels),
tx.Bucket(bucketOpenDMs),
)
})
}
func (s *BoltStore) GetServer(user *storage.User, address string) (*storage.Server, error) {
var server *storage.Server
func (s *BoltStore) Network(user *storage.User, address string) (*storage.Network, error) {
var network *storage.Network
err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
id := serverID(user, address)
b := tx.Bucket(bucketNetworks)
id := networkID(user, address)
v := b.Get(id)
if v == nil {
return storage.ErrNotFound
} else {
server = &storage.Server{}
server.Unmarshal(v)
network = &storage.Network{}
network.Unmarshal(v)
return nil
}
})
return server, err
return network, err
}
func (s *BoltStore) GetServers(user *storage.User) ([]*storage.Server, error) {
var servers []*storage.Server
func (s *BoltStore) Networks(user *storage.User) ([]*storage.Network, error) {
var networks []*storage.Network
s.db.View(func(tx *bolt.Tx) error {
c := tx.Bucket(bucketServers).Cursor()
c := tx.Bucket(bucketNetworks).Cursor()
for k, v := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, v = c.Next() {
server := storage.Server{}
server.Unmarshal(v)
servers = append(servers, &server)
network := storage.Network{}
network.Unmarshal(v)
networks = append(networks, &network)
}
return nil
})
return servers, nil
return networks, nil
}
func (s *BoltStore) SaveServer(user *storage.User, server *storage.Server) error {
func (s *BoltStore) SaveNetwork(user *storage.User, network *storage.Network) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
data, _ := server.Marshal(nil)
b := tx.Bucket(bucketNetworks)
data, _ := network.Marshal(nil)
return b.Put(serverID(user, server.Host), data)
return b.Put(networkID(user, network.Host), data)
})
}
func (s *BoltStore) RemoveServer(user *storage.User, address string) error {
func (s *BoltStore) RemoveNetwork(user *storage.User, address string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
serverID := serverID(user, address)
err := tx.Bucket(bucketServers).Delete(serverID)
networkID := networkID(user, address)
err := tx.Bucket(bucketNetworks).Delete(networkID)
if err != nil {
return err
}
return deletePrefix(serverID,
return deletePrefix(networkID,
tx.Bucket(bucketChannels),
tx.Bucket(bucketOpenDMs),
)
@ -170,16 +170,16 @@ func (s *BoltStore) RemoveServer(user *storage.User, address string) error {
func (s *BoltStore) SetNick(user *storage.User, nick, address string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
id := serverID(user, address)
b := tx.Bucket(bucketNetworks)
id := networkID(user, address)
server := storage.Server{}
network := storage.Network{}
v := b.Get(id)
if v != nil {
server.Unmarshal(v)
server.Nick = nick
network.Unmarshal(v)
network.Nick = nick
data, _ := server.Marshal(nil)
data, _ := network.Marshal(nil)
return b.Put(id, data)
}
@ -187,18 +187,18 @@ func (s *BoltStore) SetNick(user *storage.User, nick, address string) error {
})
}
func (s *BoltStore) SetServerName(user *storage.User, name, address string) error {
func (s *BoltStore) SetNetworkName(user *storage.User, name, address string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
id := serverID(user, address)
b := tx.Bucket(bucketNetworks)
id := networkID(user, address)
server := storage.Server{}
network := storage.Network{}
v := b.Get(id)
if v != nil {
server.Unmarshal(v)
server.Name = name
network.Unmarshal(v)
network.Name = name
data, _ := server.Marshal(nil)
data, _ := network.Marshal(nil)
return b.Put(id, data)
}
@ -206,7 +206,7 @@ func (s *BoltStore) SetServerName(user *storage.User, name, address string) erro
})
}
func (s *BoltStore) GetChannels(user *storage.User) ([]*storage.Channel, error) {
func (s *BoltStore) Channels(user *storage.User) ([]*storage.Channel, error) {
var channels []*storage.Channel
s.db.View(func(tx *bolt.Tx) error {
@ -224,25 +224,36 @@ func (s *BoltStore) GetChannels(user *storage.User) ([]*storage.Channel, error)
return channels, nil
}
func (s *BoltStore) AddChannel(user *storage.User, channel *storage.Channel) error {
func (s *BoltStore) SaveChannel(user *storage.User, channel *storage.Channel) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketChannels)
data, _ := channel.Marshal(nil)
return b.Put(channelID(user, channel.Server, channel.Name), data)
return b.Put(channelID(user, channel.Network, channel.Name), data)
})
}
func (s *BoltStore) RemoveChannel(user *storage.User, server, channel string) error {
func (s *BoltStore) RemoveChannel(user *storage.User, network, channel string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketChannels)
id := channelID(user, server, channel)
id := channelID(user, network, channel)
return b.Delete(id)
})
}
func (s *BoltStore) GetOpenDMs(user *storage.User) ([]storage.Tab, error) {
func (s *BoltStore) HasChannel(user *storage.User, network, channel string) bool {
has := false
s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketChannels)
has = b.Get(channelID(user, network, channel)) != nil
return nil
})
return has
}
func (s *BoltStore) OpenDMs(user *storage.User) ([]storage.Tab, error) {
var openDMs []storage.Tab
s.db.View(func(tx *bolt.Tx) error {
@ -251,8 +262,8 @@ func (s *BoltStore) GetOpenDMs(user *storage.User) ([]storage.Tab, error) {
for k, _ := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, _ = c.Next() {
tab := bytes.Split(k[8:], []byte{0})
openDMs = append(openDMs, storage.Tab{
Server: string(tab[0]),
Name: string(tab[1]),
Network: string(tab[0]),
Name: string(tab[1]),
})
}
@ -262,24 +273,24 @@ func (s *BoltStore) GetOpenDMs(user *storage.User) ([]storage.Tab, error) {
return openDMs, nil
}
func (s *BoltStore) AddOpenDM(user *storage.User, server, nick string) error {
func (s *BoltStore) AddOpenDM(user *storage.User, network, nick string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketOpenDMs)
return b.Put(channelID(user, server, nick), nil)
return b.Put(channelID(user, network, nick), nil)
})
}
func (s *BoltStore) RemoveOpenDM(user *storage.User, server, nick string) error {
func (s *BoltStore) RemoveOpenDM(user *storage.User, network, nick string) error {
return s.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketOpenDMs)
return b.Delete(channelID(user, server, nick))
return b.Delete(channelID(user, network, nick))
})
}
func (s *BoltStore) logMessage(tx *bolt.Tx, message *storage.Message) error {
b, err := tx.Bucket(bucketMessages).CreateBucketIfNotExists([]byte(message.Server + ":" + message.To))
b, err := tx.Bucket(bucketMessages).CreateBucketIfNotExists([]byte(message.Network + ":" + message.To))
if err != nil {
return err
}
@ -311,12 +322,12 @@ func (s *BoltStore) LogMessages(messages []*storage.Message) error {
})
}
func (s *BoltStore) GetMessages(server, channel string, count int, fromID string) ([]storage.Message, bool, error) {
func (s *BoltStore) Messages(network, channel string, count int, fromID string) ([]storage.Message, bool, error) {
messages := make([]storage.Message, count)
hasMore := false
s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketMessages).Bucket([]byte(server + ":" + channel))
b := tx.Bucket(bucketMessages).Bucket([]byte(network + ":" + channel))
if b == nil {
return nil
}
@ -353,11 +364,11 @@ func (s *BoltStore) GetMessages(server, channel string, count int, fromID string
return nil, false, nil
}
func (s *BoltStore) GetMessagesByID(server, channel string, ids []string) ([]storage.Message, error) {
func (s *BoltStore) MessagesByID(network, channel string, ids []string) ([]storage.Message, error) {
messages := make([]storage.Message, len(ids))
err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketMessages).Bucket([]byte(server + ":" + channel))
b := tx.Bucket(bucketMessages).Bucket([]byte(network + ":" + channel))
for i, id := range ids {
messages[i].Unmarshal(b.Get([]byte(id)))
@ -367,7 +378,7 @@ func (s *BoltStore) GetMessagesByID(server, channel string, ids []string) ([]sto
return messages, err
}
func (s *BoltStore) GetSessions() ([]*session.Session, error) {
func (s *BoltStore) Sessions() ([]*session.Session, error) {
var sessions []*session.Session
err := s.db.View(func(tx *bolt.Tx) error {
@ -422,18 +433,18 @@ func deletePrefix(prefix []byte, buckets ...*bolt.Bucket) error {
return nil
}
func serverID(user *storage.User, address string) []byte {
func networkID(user *storage.User, address string) []byte {
id := make([]byte, 8+len(address))
copy(id, user.IDBytes)
copy(id[8:], address)
return id
}
func channelID(user *storage.User, server, channel string) []byte {
id := make([]byte, 8+len(server)+1+len(channel))
func channelID(user *storage.User, network, channel string) []byte {
id := make([]byte, 8+len(network)+1+len(channel))
copy(id, user.IDBytes)
copy(id[8:], server)
copy(id[8+len(server)+1:], channel)
copy(id[8:], network)
copy(id[8+len(network)+1:], channel)
return id
}

View file

@ -124,32 +124,32 @@ type managedChannelIndex struct {
updating bool
}
func (m *ChannelIndexManager) Get(server string) (ChannelListIndex, bool) {
func (m *ChannelIndexManager) Get(network string) (ChannelListIndex, bool) {
m.lock.Lock()
defer m.lock.Unlock()
idx, ok := m.indexes[server]
idx, ok := m.indexes[network]
if !ok {
m.indexes[server] = &managedChannelIndex{
m.indexes[network] = &managedChannelIndex{
updating: true,
}
go m.timeoutUpdate(server)
go m.timeoutUpdate(network)
return nil, true
}
if !idx.updating && time.Since(idx.updatedAt) > ChannelListUpdateInterval {
idx.updating = true
go m.timeoutUpdate(server)
go m.timeoutUpdate(network)
return idx.index, true
}
return idx.index, false
}
func (m *ChannelIndexManager) Set(server string, index ChannelListIndex) {
func (m *ChannelIndexManager) Set(network string, index ChannelListIndex) {
if index.len() > 0 {
m.lock.Lock()
m.indexes[server] = &managedChannelIndex{
m.indexes[network] = &managedChannelIndex{
index: index,
updatedAt: time.Now(),
}
@ -157,12 +157,12 @@ func (m *ChannelIndexManager) Set(server string, index ChannelListIndex) {
}
}
func (m *ChannelIndexManager) timeoutUpdate(server string) {
func (m *ChannelIndexManager) timeoutUpdate(network string) {
time.Sleep(ChannelListUpdateTimeout)
m.lock.Lock()
if m.indexes[server].updating {
m.indexes[server].updating = false
if m.indexes[network].updating {
m.indexes[network].updating = false
}
m.lock.Unlock()
}

216
storage/network.go Normal file
View file

@ -0,0 +1,216 @@
package storage
import (
"fmt"
"sync"
"github.com/khlieng/dispatch/pkg/irc"
"github.com/khlieng/dispatch/version"
)
type Network struct {
Name string
Host string
Port string
TLS bool
ServerPassword string
Nick string
Username string
Realname string
Account string
Password string
Features map[string]interface{}
Connected bool
Error string
user *User
client *irc.Client
channels map[string]*Channel
lock sync.Mutex
}
func (n *Network) Save() error {
return n.user.SaveNetwork(n.Copy())
}
func (n *Network) Copy() *Network {
n.lock.Lock()
network := Network{
Name: n.Name,
Host: n.Host,
Port: n.Port,
TLS: n.TLS,
ServerPassword: n.ServerPassword,
Nick: n.Nick,
Username: n.Username,
Realname: n.Realname,
Account: n.Account,
Password: n.Password,
Features: n.Features,
Connected: n.Connected,
Error: n.Error,
user: n.user,
client: n.client,
channels: n.channels,
}
n.lock.Unlock()
return &network
}
func (n *Network) Client() *irc.Client {
return n.client
}
func (n *Network) IRCConfig() *irc.Config {
return &irc.Config{
Host: n.Host,
Port: n.Port,
TLS: n.TLS,
Nick: n.Nick,
Username: n.Username,
Realname: n.Realname,
Account: n.Account,
Password: n.Password,
Version: fmt.Sprintf("Dispatch %s (git: %s)", version.Tag, version.Commit),
Source: "https://github.com/khlieng/dispatch",
}
}
func (n *Network) SetName(name string) {
n.lock.Lock()
n.Name = name
n.lock.Unlock()
}
func (n *Network) SetNick(nick string) {
n.lock.Lock()
n.Nick = nick
n.lock.Unlock()
}
func (n *Network) SetFeatures(features map[string]interface{}) {
n.lock.Lock()
n.Features = features
n.lock.Unlock()
}
func (n *Network) SetStatus(connected bool, err string) {
n.lock.Lock()
n.Connected = connected
n.Error = err
n.lock.Unlock()
}
func (n *Network) Channel(name string) *Channel {
n.lock.Lock()
ch := n.channels[name]
n.lock.Unlock()
return ch
}
func (n *Network) Channels() []*Channel {
n.lock.Lock()
channels := make([]*Channel, 0, len(n.channels))
for _, ch := range n.channels {
channels = append(channels, ch.Copy())
}
n.lock.Unlock()
return channels
}
func (n *Network) ChannelNames() []string {
n.lock.Lock()
names := make([]string, 0, len(n.channels))
for _, ch := range n.channels {
names = append(names, ch.Name)
}
n.lock.Unlock()
return names
}
func (n *Network) NewChannel(name string) *Channel {
return &Channel{
Network: n.Host,
Name: name,
user: n.user,
}
}
func (n *Network) AddChannel(channel *Channel) {
n.lock.Lock()
n.channels[channel.Name] = channel
n.lock.Unlock()
}
func (n *Network) RemoveChannels(channels ...string) {
n.lock.Lock()
for _, name := range channels {
delete(n.channels, name)
}
n.lock.Unlock()
}
type Channel struct {
Network string
Name string
Topic string
Joined bool
user *User
lock sync.Mutex
}
func (c *Channel) Save() error {
return c.user.SaveChannel(c.Copy())
}
func (c *Channel) Copy() *Channel {
c.lock.Lock()
ch := Channel{
Network: c.Network,
Name: c.Name,
Topic: c.Topic,
Joined: c.Joined,
user: c.user,
}
c.lock.Unlock()
return &ch
}
func (c *Channel) SetTopic(topic string) {
if c == nil {
return
}
c.lock.Lock()
c.Topic = topic
c.lock.Unlock()
}
func (c *Channel) IsJoined() bool {
if c == nil {
return false
}
c.lock.Lock()
joined := c.Joined
c.lock.Unlock()
return joined
}
func (c *Channel) SetJoined(joined bool) {
if c == nil {
return
}
c.lock.Lock()
c.Joined = joined
c.lock.Unlock()
}

377
storage/network_easyjson.go Normal file
View file

@ -0,0 +1,377 @@
//v1: false// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package storage
import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)
func easyjsonC5839400DecodeGithubComKhliengDispatchStorage(in *jlexer.Lexer, out *Network) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "name":
out.Name = string(in.String())
case "host":
out.Host = string(in.String())
case "port":
out.Port = string(in.String())
case "tls":
out.TLS = bool(in.Bool())
case "serverPassword":
out.ServerPassword = string(in.String())
case "nick":
out.Nick = string(in.String())
case "username":
out.Username = string(in.String())
case "realname":
out.Realname = string(in.String())
case "account":
out.Account = string(in.String())
case "password":
out.Password = string(in.String())
case "features":
if in.IsNull() {
in.Skip()
} else {
in.Delim('{')
if !in.IsDelim('}') {
out.Features = make(map[string]interface{})
} else {
out.Features = nil
}
for !in.IsDelim('}') {
key := string(in.String())
in.WantColon()
var v1 interface{}
if m, ok := v1.(easyjson.Unmarshaler); ok {
m.UnmarshalEasyJSON(in)
} else if m, ok := v1.(json.Unmarshaler); ok {
_ = m.UnmarshalJSON(in.Raw())
} else {
v1 = in.Interface()
}
(out.Features)[key] = v1
in.WantComma()
}
in.Delim('}')
}
case "connected":
out.Connected = bool(in.Bool())
case "error":
out.Error = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonC5839400EncodeGithubComKhliengDispatchStorage(out *jwriter.Writer, in Network) {
out.RawByte('{')
first := true
_ = first
if in.Name != "" {
const prefix string = ",\"name\":"
first = false
out.RawString(prefix[1:])
out.String(string(in.Name))
}
if in.Host != "" {
const prefix string = ",\"host\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Host))
}
if in.Port != "" {
const prefix string = ",\"port\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Port))
}
if in.TLS {
const prefix string = ",\"tls\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Bool(bool(in.TLS))
}
if in.ServerPassword != "" {
const prefix string = ",\"serverPassword\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.ServerPassword))
}
if in.Nick != "" {
const prefix string = ",\"nick\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Nick))
}
if in.Username != "" {
const prefix string = ",\"username\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Username))
}
if in.Realname != "" {
const prefix string = ",\"realname\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Realname))
}
if in.Account != "" {
const prefix string = ",\"account\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Account))
}
if in.Password != "" {
const prefix string = ",\"password\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Password))
}
if len(in.Features) != 0 {
const prefix string = ",\"features\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
{
out.RawByte('{')
v2First := true
for v2Name, v2Value := range in.Features {
if v2First {
v2First = false
} else {
out.RawByte(',')
}
out.String(string(v2Name))
out.RawByte(':')
if m, ok := v2Value.(easyjson.Marshaler); ok {
m.MarshalEasyJSON(out)
} else if m, ok := v2Value.(json.Marshaler); ok {
out.Raw(m.MarshalJSON())
} else {
out.Raw(json.Marshal(v2Value))
}
}
out.RawByte('}')
}
}
if in.Connected {
const prefix string = ",\"connected\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Bool(bool(in.Connected))
}
if in.Error != "" {
const prefix string = ",\"error\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Error))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v Network) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonC5839400EncodeGithubComKhliengDispatchStorage(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v Network) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonC5839400EncodeGithubComKhliengDispatchStorage(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *Network) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonC5839400DecodeGithubComKhliengDispatchStorage(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *Network) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonC5839400DecodeGithubComKhliengDispatchStorage(l, v)
}
func easyjsonC5839400DecodeGithubComKhliengDispatchStorage1(in *jlexer.Lexer, out *Channel) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "network":
out.Network = string(in.String())
case "name":
out.Name = string(in.String())
case "topic":
out.Topic = string(in.String())
case "joined":
out.Joined = bool(in.Bool())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonC5839400EncodeGithubComKhliengDispatchStorage1(out *jwriter.Writer, in Channel) {
out.RawByte('{')
first := true
_ = first
if in.Network != "" {
const prefix string = ",\"network\":"
first = false
out.RawString(prefix[1:])
out.String(string(in.Network))
}
if in.Name != "" {
const prefix string = ",\"name\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Name))
}
if in.Topic != "" {
const prefix string = ",\"topic\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.Topic))
}
if in.Joined {
const prefix string = ",\"joined\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.Bool(bool(in.Joined))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v Channel) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonC5839400EncodeGithubComKhliengDispatchStorage1(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v Channel) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonC5839400EncodeGithubComKhliengDispatchStorage1(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *Channel) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonC5839400DecodeGithubComKhliengDispatchStorage1(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *Channel) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonC5839400DecodeGithubComKhliengDispatchStorage1(l, v)
}

View file

@ -31,26 +31,27 @@ var (
)
type Store interface {
GetUsers() ([]*User, error)
Users() ([]*User, error)
SaveUser(user *User) error
DeleteUser(user *User) error
GetServer(user *User, host string) (*Server, error)
GetServers(user *User) ([]*Server, error)
SaveServer(user *User, server *Server) error
RemoveServer(user *User, host string) error
Network(user *User, host string) (*Network, error)
Networks(user *User) ([]*Network, error)
SaveNetwork(user *User, network *Network) error
RemoveNetwork(user *User, host string) error
GetChannels(user *User) ([]*Channel, error)
AddChannel(user *User, channel *Channel) error
RemoveChannel(user *User, server, channel string) error
Channels(user *User) ([]*Channel, error)
HasChannel(user *User, network, channel string) bool
SaveChannel(user *User, channel *Channel) error
RemoveChannel(user *User, network, channel string) error
GetOpenDMs(user *User) ([]Tab, error)
AddOpenDM(user *User, server, nick string) error
RemoveOpenDM(user *User, server, nick string) error
OpenDMs(user *User) ([]Tab, error)
AddOpenDM(user *User, network, nick string) error
RemoveOpenDM(user *User, network, nick string) error
}
type SessionStore interface {
GetSessions() ([]*session.Session, error)
Sessions() ([]*session.Session, error)
SaveSession(session *session.Session) error
DeleteSession(key string) error
}
@ -58,15 +59,15 @@ type SessionStore interface {
type MessageStore interface {
LogMessage(message *Message) error
LogMessages(messages []*Message) error
GetMessages(server, channel string, count int, fromID string) ([]Message, bool, error)
GetMessagesByID(server, channel string, ids []string) ([]Message, error)
Messages(network, channel string, count int, fromID string) ([]Message, bool, error)
MessagesByID(network, channel string, ids []string) ([]Message, error)
Close()
}
type MessageStoreCreator func(*User) (MessageStore, error)
type MessageSearchProvider interface {
SearchMessages(server, channel, q string) ([]string, error)
SearchMessages(network, channel, q string) ([]string, error)
Index(id string, message *Message) error
Close()
}

View file

@ -9,7 +9,7 @@ struct ClientSettings {
ColoredNicks bool
}
struct Server {
struct Network {
Name string
Host string
Port string
@ -23,7 +23,7 @@ struct Server {
}
struct Channel {
Server string
Network string
Name string
}

View file

@ -238,7 +238,7 @@ func (d *ClientSettings) Unmarshal(buf []byte) (uint64, error) {
return i + 1, nil
}
func (d *Server) Size() (s uint64) {
func (d *Network) Size() (s uint64) {
{
l := uint64(len(d.Name))
@ -378,7 +378,7 @@ func (d *Server) Size() (s uint64) {
s += 1
return
}
func (d *Server) Marshal(buf []byte) ([]byte, error) {
func (d *Network) Marshal(buf []byte) ([]byte, error) {
size := d.Size()
{
if uint64(cap(buf)) >= size {
@ -570,7 +570,7 @@ func (d *Server) Marshal(buf []byte) ([]byte, error) {
return buf[:i+1], nil
}
func (d *Server) Unmarshal(buf []byte) (uint64, error) {
func (d *Network) Unmarshal(buf []byte) (uint64, error) {
i := uint64(0)
{
@ -762,7 +762,7 @@ func (d *Server) Unmarshal(buf []byte) (uint64, error) {
func (d *Channel) Size() (s uint64) {
{
l := uint64(len(d.Server))
l := uint64(len(d.Network))
{
@ -805,7 +805,7 @@ func (d *Channel) Marshal(buf []byte) ([]byte, error) {
i := uint64(0)
{
l := uint64(len(d.Server))
l := uint64(len(d.Network))
{
@ -820,7 +820,7 @@ func (d *Channel) Marshal(buf []byte) ([]byte, error) {
i++
}
copy(buf[i+0:], d.Server)
copy(buf[i+0:], d.Network)
i += l
}
{
@ -865,7 +865,7 @@ func (d *Channel) Unmarshal(buf []byte) (uint64, error) {
l = t
}
d.Server = string(buf[i+0 : i+0+l])
d.Network = string(buf[i+0 : i+0+l])
i += l
}
{

View file

@ -6,6 +6,7 @@ import (
"sync"
"time"
"github.com/khlieng/dispatch/pkg/irc"
"github.com/kjk/betterguid"
)
@ -58,7 +59,7 @@ func NewUser(store Store) (*User, error) {
}
func LoadUsers(store Store) ([]*User, error) {
users, err := store.GetUsers()
users, err := store.Users()
if err != nil {
return nil, err
}
@ -76,15 +77,15 @@ func LoadUsers(store Store) ([]*User, error) {
user.lastMessages = map[string]map[string]*Message{}
user.loadCertificate()
channels, err := user.GetChannels()
channels, err := user.Channels()
if err != nil {
return nil, err
}
for _, channel := range channels {
messages, _, err := user.GetLastMessages(channel.Server, channel.Name, 1)
messages, _, err := user.LastMessages(channel.Network, channel.Name, 1)
if err == nil && len(messages) == 1 {
user.lastMessages[channel.Server] = map[string]*Message{
user.lastMessages[channel.Network] = map[string]*Message{
channel.Name: &messages[0],
}
}
@ -131,7 +132,7 @@ func DefaultClientSettings() *ClientSettings {
}
}
func (u *User) GetClientSettings() *ClientSettings {
func (u *User) ClientSettings() *ClientSettings {
u.lock.Lock()
settings := *u.clientSettings
u.lock.Unlock()
@ -158,91 +159,88 @@ func (u *User) UnmarshalClientSettingsJSON(b []byte) error {
return u.store.SaveUser(u)
}
type Server struct {
Name string
Host string
Port string
TLS bool
ServerPassword string
Nick string
Username string
Realname string
Account string
Password string
func (u *User) NewNetwork(template *Network, client *irc.Client) *Network {
if template == nil {
template = &Network{}
}
template.user = u
template.client = client
template.channels = map[string]*Channel{}
return template
}
func (u *User) GetServer(address string) (*Server, error) {
return u.store.GetServer(u, address)
func (u *User) Network(address string) (*Network, error) {
return u.store.Network(u, address)
}
func (u *User) GetServers() ([]*Server, error) {
return u.store.GetServers(u)
func (u *User) Networks() ([]*Network, error) {
return u.store.Networks(u)
}
func (u *User) AddServer(server *Server) error {
return u.store.SaveServer(u, server)
func (u *User) SaveNetwork(network *Network) error {
return u.store.SaveNetwork(u, network)
}
func (u *User) RemoveServer(address string) error {
return u.store.RemoveServer(u, address)
func (u *User) RemoveNetwork(address string) error {
return u.store.RemoveNetwork(u, address)
}
func (u *User) SetNick(nick, address string) error {
server, err := u.GetServer(address)
network, err := u.Network(address)
if err != nil {
return err
}
server.Nick = nick
return u.AddServer(server)
network.Nick = nick
return u.SaveNetwork(network)
}
func (u *User) SetServerName(name, address string) error {
server, err := u.GetServer(address)
func (u *User) SetNetworkName(name, address string) error {
network, err := u.Network(address)
if err != nil {
return err
}
server.Name = name
return u.AddServer(server)
network.Name = name
return u.SaveNetwork(network)
}
type Channel struct {
Server string
Name string
Topic string
func (u *User) Channels() ([]*Channel, error) {
return u.store.Channels(u)
}
func (u *User) GetChannels() ([]*Channel, error) {
return u.store.GetChannels(u)
func (u *User) SaveChannel(channel *Channel) error {
return u.store.SaveChannel(u, channel)
}
func (u *User) AddChannel(channel *Channel) error {
return u.store.AddChannel(u, channel)
func (u *User) RemoveChannel(network, channel string) error {
return u.store.RemoveChannel(u, network, channel)
}
func (u *User) RemoveChannel(server, channel string) error {
return u.store.RemoveChannel(u, server, channel)
func (u *User) HasChannel(network, channel string) bool {
return u.store.HasChannel(u, network, channel)
}
type Tab struct {
Server string
Name string
Network string
Name string
}
func (u *User) GetOpenDMs() ([]Tab, error) {
return u.store.GetOpenDMs(u)
func (u *User) OpenDMs() ([]Tab, error) {
return u.store.OpenDMs(u)
}
func (u *User) AddOpenDM(server, nick string) error {
return u.store.AddOpenDM(u, server, nick)
func (u *User) AddOpenDM(network, nick string) error {
return u.store.AddOpenDM(u, network, nick)
}
func (u *User) RemoveOpenDM(server, nick string) error {
return u.store.RemoveOpenDM(u, server, nick)
func (u *User) RemoveOpenDM(network, nick string) error {
return u.store.RemoveOpenDM(u, network, nick)
}
type Message struct {
ID string `json:"-" bleve:"-"`
Server string `json:"-" bleve:"server"`
Network string `json:"-" bleve:"server"`
From string `bleve:"-"`
To string `json:"-" bleve:"to"`
Content string `bleve:"content"`
@ -267,7 +265,7 @@ func (u *User) LogMessage(msg *Message) error {
msg.To = msg.From
}
u.setLastMessage(msg.Server, msg.To, msg)
u.setLastMessage(msg.Network, msg.To, msg)
err := u.messageLog.LogMessage(msg)
if err != nil {
@ -282,7 +280,7 @@ type Event struct {
Time int64
}
func (u *User) LogEvent(server, name string, params []string, channels ...string) error {
func (u *User) LogEvent(network, name string, params []string, channels ...string) error {
now := time.Now().Unix()
event := Event{
Type: name,
@ -291,11 +289,11 @@ func (u *User) LogEvent(server, name string, params []string, channels ...string
}
for _, channel := range channels {
lastMessage := u.getLastMessage(server, channel)
lastMessage := u.getLastMessage(network, channel)
if lastMessage != nil && shouldCollapse(lastMessage, event) {
lastMessage.Events = append(lastMessage.Events, event)
u.setLastMessage(server, channel, lastMessage)
u.setLastMessage(network, channel, lastMessage)
err := u.messageLog.LogMessage(lastMessage)
if err != nil {
@ -303,13 +301,13 @@ func (u *User) LogEvent(server, name string, params []string, channels ...string
}
} else {
msg := &Message{
ID: betterguid.New(),
Server: server,
To: channel,
Time: now,
Events: []Event{event},
ID: betterguid.New(),
Network: network,
To: channel,
Time: now,
Events: []Event{event},
}
u.setLastMessage(server, channel, msg)
u.setLastMessage(network, channel, msg)
err := u.messageLog.LogMessage(msg)
if err != nil {
@ -338,15 +336,15 @@ func shouldCollapse(msg *Message, event Event) bool {
return matches == 2
}
func (u *User) getLastMessage(server, channel string) *Message {
func (u *User) getLastMessage(network, channel string) *Message {
u.lock.Lock()
defer u.lock.Unlock()
if _, ok := u.lastMessages[server]; !ok {
if _, ok := u.lastMessages[network]; !ok {
return nil
}
last := u.lastMessages[server][channel]
last := u.lastMessages[network][channel]
if last != nil {
msg := *last
return &msg
@ -354,30 +352,30 @@ func (u *User) getLastMessage(server, channel string) *Message {
return nil
}
func (u *User) setLastMessage(server, channel string, msg *Message) {
func (u *User) setLastMessage(network, channel string, msg *Message) {
u.lock.Lock()
if _, ok := u.lastMessages[server]; !ok {
u.lastMessages[server] = map[string]*Message{}
if _, ok := u.lastMessages[network]; !ok {
u.lastMessages[network] = map[string]*Message{}
}
u.lastMessages[server][channel] = msg
u.lastMessages[network][channel] = msg
u.lock.Unlock()
}
func (u *User) GetMessages(server, channel string, count int, fromID string) ([]Message, bool, error) {
return u.messageLog.GetMessages(server, channel, count, fromID)
func (u *User) Messages(network, channel string, count int, fromID string) ([]Message, bool, error) {
return u.messageLog.Messages(network, channel, count, fromID)
}
func (u *User) GetLastMessages(server, channel string, count int) ([]Message, bool, error) {
return u.GetMessages(server, channel, count, "")
func (u *User) LastMessages(network, channel string, count int) ([]Message, bool, error) {
return u.Messages(network, channel, count, "")
}
func (u *User) SearchMessages(server, channel, q string) ([]Message, error) {
ids, err := u.messageIndex.SearchMessages(server, channel, q)
func (u *User) SearchMessages(network, channel, q string) ([]Message, error) {
ids, err := u.messageIndex.SearchMessages(network, channel, q)
if err != nil {
return nil, err
}
return u.messageLog.GetMessagesByID(server, channel, ids)
return u.messageLog.MessagesByID(network, channel, ids)
}

View file

@ -34,23 +34,23 @@ func TestUser(t *testing.T) {
user, err := storage.NewUser(db)
assert.Nil(t, err)
srv := &storage.Server{
srv := &storage.Network{
Name: "freenode",
Host: "irc.freenode.net",
Nick: "test",
}
chan1 := &storage.Channel{
Server: srv.Host,
Name: "#test",
Network: srv.Host,
Name: "#test",
}
chan2 := &storage.Channel{
Server: srv.Host,
Name: "#testing",
Network: srv.Host,
Name: "#testing",
}
user.AddServer(srv)
user.AddChannel(chan1)
user.AddChannel(chan2)
user.SaveNetwork(srv)
user.SaveChannel(chan1)
user.SaveChannel(chan2)
users, err := storage.LoadUsers(db)
assert.Nil(t, err)
@ -59,52 +59,52 @@ func TestUser(t *testing.T) {
user = users[0]
assert.Equal(t, uint64(1), user.ID)
servers, err := user.GetServers()
servers, err := user.Networks()
assert.Len(t, servers, 1)
assert.Equal(t, srv, servers[0])
channels, err := user.GetChannels()
channels, err := user.Channels()
assert.Len(t, channels, 2)
assert.Equal(t, chan1, channels[0])
assert.Equal(t, chan2, channels[1])
user.SetNick("bob", srv.Host)
servers, err = user.GetServers()
servers, err = user.Networks()
assert.Equal(t, "bob", servers[0].Nick)
user.SetServerName("cake", srv.Host)
servers, err = user.GetServers()
user.SetNetworkName("cake", srv.Host)
servers, err = user.Networks()
assert.Equal(t, "cake", servers[0].Name)
user.RemoveChannel(srv.Host, chan1.Name)
channels, err = user.GetChannels()
channels, err = user.Channels()
assert.Len(t, channels, 1)
assert.Equal(t, chan2, channels[0])
user.RemoveServer(srv.Host)
servers, err = user.GetServers()
user.RemoveNetwork(srv.Host)
servers, err = user.Networks()
assert.Len(t, servers, 0)
channels, err = user.GetChannels()
channels, err = user.Channels()
assert.Len(t, channels, 0)
user.AddOpenDM(srv.Host, "cake")
openDMs, err := user.GetOpenDMs()
openDMs, err := user.OpenDMs()
assert.Nil(t, err)
assert.Len(t, openDMs, 1)
err = user.RemoveOpenDM(srv.Host, "cake")
assert.Nil(t, err)
openDMs, err = user.GetOpenDMs()
openDMs, err = user.OpenDMs()
assert.Nil(t, err)
assert.Len(t, openDMs, 0)
settings := user.GetClientSettings()
settings := user.ClientSettings()
assert.NotNil(t, settings)
assert.Equal(t, storage.DefaultClientSettings(), settings)
settings.ColoredNicks = !settings.ColoredNicks
err = user.SetClientSettings(settings)
assert.Nil(t, err)
assert.Equal(t, settings, user.GetClientSettings())
assert.Equal(t, settings, user.ClientSettings())
assert.NotEqual(t, settings, storage.DefaultClientSettings())
user.AddOpenDM(srv.Host, "cake")
@ -113,7 +113,7 @@ func TestUser(t *testing.T) {
_, err = os.Stat(storage.Path.User(user.Username))
assert.True(t, os.IsNotExist(err))
openDMs, err = user.GetOpenDMs()
openDMs, err = user.OpenDMs()
assert.Nil(t, err)
assert.Len(t, openDMs, 0)
@ -143,12 +143,12 @@ func TestMessages(t *testing.T) {
os.MkdirAll(storage.Path.User(user.Username), 0700)
messages, hasMore, err := user.GetMessages("irc.freenode.net", "#go-nuts", 10, "6")
messages, hasMore, err := user.Messages("irc.freenode.net", "#go-nuts", 10, "6")
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 0)
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 10)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 10)
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 0)
@ -163,7 +163,7 @@ func TestMessages(t *testing.T) {
ids = append(ids, id)
err = user.LogMessage(&storage.Message{
ID: id,
Server: "irc.freenode.net",
Network: "irc.freenode.net",
From: "nick",
To: "#go-nuts",
Content: "message" + strconv.Itoa(i),
@ -171,35 +171,35 @@ func TestMessages(t *testing.T) {
assert.Nil(t, err)
}
messages, hasMore, err = user.GetMessages("irc.freenode.net", "#go-nuts", 10, ids[4])
messages, hasMore, err = user.Messages("irc.freenode.net", "#go-nuts", 10, ids[4])
assert.Equal(t, "message0", messages[0].Content)
assert.Equal(t, "message3", messages[3].Content)
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 4)
messages, hasMore, err = user.GetMessages("irc.freenode.net", "#go-nuts", 10, betterguid.New())
messages, hasMore, err = user.Messages("irc.freenode.net", "#go-nuts", 10, betterguid.New())
assert.Equal(t, "message0", messages[0].Content)
assert.Equal(t, "message4", messages[4].Content)
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 5)
messages, hasMore, err = user.GetMessages("irc.freenode.net", "#go-nuts", 10, ids[2])
messages, hasMore, err = user.Messages("irc.freenode.net", "#go-nuts", 10, ids[2])
assert.Equal(t, "message0", messages[0].Content)
assert.Equal(t, "message1", messages[1].Content)
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 2)
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 10)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 10)
assert.Equal(t, "message0", messages[0].Content)
assert.Equal(t, "message4", messages[4].Content)
assert.Nil(t, err)
assert.False(t, hasMore)
assert.Len(t, messages, 5)
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 4)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 4)
assert.Equal(t, "message1", messages[0].Content)
assert.Equal(t, "message4", messages[3].Content)
assert.Nil(t, err)
@ -211,7 +211,7 @@ func TestMessages(t *testing.T) {
assert.True(t, len(messages) > 0)
user.LogEvent("irc.freenode.net", "join", []string{"bob"}, "#go-nuts")
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 1)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 1)
assert.Zero(t, messages[0].Content)
assert.Nil(t, err)
assert.True(t, hasMore)
@ -220,7 +220,7 @@ func TestMessages(t *testing.T) {
assert.NotZero(t, messages[0].Events[0].Time)
user.LogEvent("irc.freenode.net", "part", []string{"bob"}, "#go-nuts")
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 1)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 1)
assert.Zero(t, messages[0].Content)
assert.Nil(t, err)
assert.True(t, hasMore)
@ -229,7 +229,7 @@ func TestMessages(t *testing.T) {
assert.NotZero(t, messages[0].Events[0].Time)
user.LogEvent("irc.freenode.net", "nick", []string{"bob", "rob"}, "#go-nuts")
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 1)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 1)
assert.Zero(t, messages[0].Content)
assert.Nil(t, err)
assert.True(t, hasMore)
@ -238,7 +238,7 @@ func TestMessages(t *testing.T) {
assert.NotZero(t, messages[0].Events[0].Time)
user.LogEvent("irc.freenode.net", "quit", []string{"rob", "bored"}, "#go-nuts")
messages, hasMore, err = user.GetLastMessages("irc.freenode.net", "#go-nuts", 1)
messages, hasMore, err = user.LastMessages("irc.freenode.net", "#go-nuts", 1)
assert.Zero(t, messages[0].Content)
assert.Nil(t, err)
assert.True(t, hasMore)