mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
persistent channels persisted to a sqlite db
This commit is contained in:
parent
de5538f5d5
commit
02abeeb164
@ -40,5 +40,6 @@ byte strings. You can generate them with e.g. `ergonomadic -genpasswd
|
|||||||
```sh
|
```sh
|
||||||
go get
|
go get
|
||||||
go install
|
go install
|
||||||
|
ergonomadic -conf '/path/to/config.json' -initdb
|
||||||
ergonomadic -conf '/path/to/config.json'
|
ergonomadic -conf '/path/to/config.json'
|
||||||
```
|
```
|
||||||
|
@ -2,11 +2,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/go.crypto/bcrypt"
|
"code.google.com/p/go.crypto/bcrypt"
|
||||||
|
"database/sql"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jlatt/ergonomadic/irc"
|
"github.com/jlatt/ergonomadic/irc"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func genPasswd(passwd string) {
|
func genPasswd(passwd string) {
|
||||||
@ -18,8 +21,30 @@ func genPasswd(passwd string) {
|
|||||||
fmt.Println(encoded)
|
fmt.Println(encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initDB(config *irc.Config) {
|
||||||
|
os.Remove(config.Database())
|
||||||
|
|
||||||
|
db, err := sql.Open("sqlite3", config.Database())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
_, err = db.Exec(`
|
||||||
|
CREATE TABLE channel (
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
flags TEXT,
|
||||||
|
key TEXT,
|
||||||
|
topic TEXT,
|
||||||
|
user_limit INTEGER)`)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
conf := flag.String("conf", "ergonomadic.json", "ergonomadic config file")
|
conf := flag.String("conf", "ergonomadic.json", "ergonomadic config file")
|
||||||
|
initdb := flag.Bool("initdb", false, "initialize database")
|
||||||
passwd := flag.String("genpasswd", "", "bcrypt a password")
|
passwd := flag.String("genpasswd", "", "bcrypt a password")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@ -31,9 +56,14 @@ func main() {
|
|||||||
config, err := irc.LoadConfig(*conf)
|
config, err := irc.LoadConfig(*conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *initdb {
|
||||||
|
initDB(config)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move to data structures
|
||||||
irc.DEBUG_NET = config.Debug["net"]
|
irc.DEBUG_NET = config.Debug["net"]
|
||||||
irc.DEBUG_CLIENT = config.Debug["client"]
|
irc.DEBUG_CLIENT = config.Debug["client"]
|
||||||
irc.DEBUG_CHANNEL = config.Debug["channel"]
|
irc.DEBUG_CHANNEL = config.Debug["channel"]
|
||||||
|
@ -33,7 +33,14 @@ func NewChannel(s *Server, name string) *Channel {
|
|||||||
name: name,
|
name: name,
|
||||||
server: s,
|
server: s,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.channels[name] = channel
|
s.channels[name] = channel
|
||||||
|
s.db.Exec(`INSERT INTO channel
|
||||||
|
(name, flags, key, topic, user_limit)
|
||||||
|
VALUES (?, ?, ?, ?, ?)`,
|
||||||
|
channel.name, channel.flags.String(), channel.key, channel.topic,
|
||||||
|
channel.userLimit)
|
||||||
|
|
||||||
return channel
|
return channel
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +149,9 @@ func (channel *Channel) Join(client *Client, key string) {
|
|||||||
client.channels.Add(channel)
|
client.channels.Add(channel)
|
||||||
channel.members.Add(client)
|
channel.members.Add(client)
|
||||||
if len(channel.members) == 1 {
|
if len(channel.members) == 1 {
|
||||||
channel.members[client][ChannelCreator] = true
|
if !channel.flags[Persistent] {
|
||||||
|
channel.members[client][ChannelCreator] = true
|
||||||
|
}
|
||||||
channel.members[client][ChannelOperator] = true
|
channel.members[client][ChannelOperator] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +207,10 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel.topic = topic
|
channel.topic = topic
|
||||||
|
channel.server.db.Exec(`
|
||||||
|
UPDATE channel
|
||||||
|
SET topic = ?
|
||||||
|
WHERE name = ?`, channel.topic, channel.name)
|
||||||
|
|
||||||
reply := RplTopicMsg(client, channel)
|
reply := RplTopicMsg(client, channel)
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
@ -361,6 +374,11 @@ func (channel *Channel) Mode(client *Client, changes ChannelModeChanges) {
|
|||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
member.Reply(reply)
|
member.Reply(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.server.db.Exec(`
|
||||||
|
UPDATE channel
|
||||||
|
SET flags = ?
|
||||||
|
WHERE name = ?`, channel.flags.String(), channel.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,11 @@ type Config struct {
|
|||||||
Name string
|
Name string
|
||||||
Operators []OperatorConfig
|
Operators []OperatorConfig
|
||||||
Password string
|
Password string
|
||||||
|
directory string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *Config) Database() string {
|
||||||
|
return filepath.Join(conf.directory, "ergonomadic.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *Config) PasswordBytes() []byte {
|
func (conf *Config) PasswordBytes() []byte {
|
||||||
@ -75,9 +80,8 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := filepath.Dir(filename)
|
config.directory = filepath.Dir(filename)
|
||||||
config.MOTD = filepath.Join(dir, config.MOTD)
|
config.MOTD = filepath.Join(config.directory, config.MOTD)
|
||||||
|
|
||||||
for _, lconf := range config.Listeners {
|
for _, lconf := range config.Listeners {
|
||||||
if lconf.Net == "" {
|
if lconf.Net == "" {
|
||||||
lconf.Net = "tcp"
|
lconf.Net = "tcp"
|
||||||
|
@ -4,11 +4,14 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"database/sql"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
@ -21,30 +24,65 @@ type Server struct {
|
|||||||
clients ClientNameMap
|
clients ClientNameMap
|
||||||
commands chan Command
|
commands chan Command
|
||||||
ctime time.Time
|
ctime time.Time
|
||||||
|
db *sql.DB
|
||||||
idle chan *Client
|
idle chan *Client
|
||||||
motdFile string
|
motdFile string
|
||||||
name string
|
name string
|
||||||
newConns chan net.Conn
|
newConns chan net.Conn
|
||||||
operators map[string][]byte
|
operators map[string][]byte
|
||||||
password []byte
|
password []byte
|
||||||
|
signals chan os.Signal
|
||||||
timeout chan *Client
|
timeout chan *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config *Config) *Server {
|
func NewServer(config *Config) *Server {
|
||||||
|
db, err := sql.Open("sqlite3", config.Database())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
server := &Server{
|
server := &Server{
|
||||||
channels: make(ChannelNameMap),
|
channels: make(ChannelNameMap),
|
||||||
clients: make(ClientNameMap),
|
clients: make(ClientNameMap),
|
||||||
commands: make(chan Command, 16),
|
commands: make(chan Command, 16),
|
||||||
ctime: time.Now(),
|
ctime: time.Now(),
|
||||||
|
db: db,
|
||||||
idle: make(chan *Client, 16),
|
idle: make(chan *Client, 16),
|
||||||
motdFile: config.MOTD,
|
motdFile: config.MOTD,
|
||||||
name: config.Name,
|
name: config.Name,
|
||||||
newConns: make(chan net.Conn, 16),
|
newConns: make(chan net.Conn, 16),
|
||||||
operators: config.OperatorsMap(),
|
operators: config.OperatorsMap(),
|
||||||
password: config.PasswordBytes(),
|
password: config.PasswordBytes(),
|
||||||
|
signals: make(chan os.Signal, 1),
|
||||||
timeout: make(chan *Client, 16),
|
timeout: make(chan *Client, 16),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal.Notify(server.signals, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
|
rows, err := db.Query(`
|
||||||
|
SELECT name, flags, key, topic, user_limit
|
||||||
|
FROM channel`)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var name, flags, key, topic string
|
||||||
|
var userLimit uint64
|
||||||
|
err = rows.Scan(&name, &flags, &key, &topic, &userLimit)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := NewChannel(server, name)
|
||||||
|
for flag := range flags {
|
||||||
|
channel.flags[ChannelMode(flag)] = true
|
||||||
|
}
|
||||||
|
channel.key = key
|
||||||
|
channel.topic = topic
|
||||||
|
channel.userLimit = userLimit
|
||||||
|
}
|
||||||
|
|
||||||
for _, listenerConf := range config.Listeners {
|
for _, listenerConf := range config.Listeners {
|
||||||
go server.listen(listenerConf)
|
go server.listen(listenerConf)
|
||||||
}
|
}
|
||||||
@ -97,8 +135,14 @@ func (server *Server) processCommand(cmd Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) Run() {
|
func (server *Server) Run() {
|
||||||
for {
|
done := false
|
||||||
|
for !done {
|
||||||
select {
|
select {
|
||||||
|
case <-server.signals:
|
||||||
|
server.db.Close()
|
||||||
|
done = true
|
||||||
|
continue
|
||||||
|
|
||||||
case conn := <-server.newConns:
|
case conn := <-server.newConns:
|
||||||
NewClient(server, conn)
|
NewClient(server, conn)
|
||||||
|
|
||||||
|
10
irc/types.go
10
irc/types.go
@ -106,6 +106,16 @@ func (clients ClientNameMap) Remove(client *Client) error {
|
|||||||
|
|
||||||
type ChannelModeSet map[ChannelMode]bool
|
type ChannelModeSet map[ChannelMode]bool
|
||||||
|
|
||||||
|
func (set ChannelModeSet) String() string {
|
||||||
|
strs := make([]string, len(set))
|
||||||
|
index := 0
|
||||||
|
for mode := range set {
|
||||||
|
strs[index] = mode.String()
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
return strings.Join(strs, "")
|
||||||
|
}
|
||||||
|
|
||||||
type ClientSet map[*Client]bool
|
type ClientSet map[*Client]bool
|
||||||
|
|
||||||
func (clients ClientSet) Add(client *Client) {
|
func (clients ClientSet) Add(client *Client) {
|
||||||
|
Loading…
Reference in New Issue
Block a user