mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
get rid of user abstraction, services
This commit is contained in:
parent
f133f3691d
commit
f04dd7c5d5
6
build.sh
6
build.sh
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
export GOPATH="$PWD"
|
||||
go get "code.google.com/p/go.crypto/bcrypt"
|
||||
go get "github.com/mattn/go-sqlite3"
|
||||
go install ergonomadic genpasswd ergonomadicdb
|
||||
#go get "code.google.com/p/go.crypto/bcrypt"
|
||||
#go get "github.com/mattn/go-sqlite3"
|
||||
go install ergonomadic genpasswd
|
||||
|
@ -9,82 +9,41 @@ const (
|
||||
)
|
||||
|
||||
type Channel struct {
|
||||
id *RowId
|
||||
server *Server
|
||||
commands chan<- ChannelCommand
|
||||
replies chan<- Reply
|
||||
name string
|
||||
key string
|
||||
topic string
|
||||
members UserSet
|
||||
members ClientSet
|
||||
name string
|
||||
noOutside bool
|
||||
password string
|
||||
replies chan<- Reply
|
||||
server *Server
|
||||
topic string
|
||||
}
|
||||
|
||||
type ChannelSet map[*Channel]bool
|
||||
|
||||
func (set ChannelSet) Add(channel *Channel) {
|
||||
set[channel] = true
|
||||
}
|
||||
|
||||
func (set ChannelSet) Remove(channel *Channel) {
|
||||
delete(set, channel)
|
||||
}
|
||||
|
||||
func (set ChannelSet) Ids() (ids []RowId) {
|
||||
ids = make([]RowId, len(set))
|
||||
var i = 0
|
||||
for channel := range set {
|
||||
ids[i] = *(channel.id)
|
||||
i++
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
type ChannelCommand interface {
|
||||
Command
|
||||
HandleChannel(channel *Channel)
|
||||
}
|
||||
|
||||
// NewChannel creates a new channel from a `Server` and a `name` string, which
|
||||
// must be unique on the server.
|
||||
// NewChannel creates a new channel from a `Server` and a `name`
|
||||
// string, which must be unique on the server.
|
||||
func NewChannel(s *Server, name string) *Channel {
|
||||
commands := make(chan ChannelCommand)
|
||||
replies := make(chan Reply)
|
||||
channel := &Channel{
|
||||
name: name,
|
||||
members: make(UserSet),
|
||||
members: make(ClientSet),
|
||||
server: s,
|
||||
commands: commands,
|
||||
replies: replies,
|
||||
}
|
||||
go channel.receiveCommands(commands)
|
||||
go channel.receiveReplies(replies)
|
||||
Save(s.db, channel)
|
||||
return channel
|
||||
}
|
||||
|
||||
func (channel *Channel) Save(q Queryable) bool {
|
||||
if channel.id == nil {
|
||||
if err := InsertChannel(q, channel); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
channelId, err := FindChannelIdByName(q, channel.name)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
channel.id = &channelId
|
||||
} else {
|
||||
if err := UpdateChannel(q, channel); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (channel *Channel) receiveCommands(commands <-chan ChannelCommand) {
|
||||
for command := range commands {
|
||||
if DEBUG_CHANNEL {
|
||||
@ -99,16 +58,13 @@ func (channel *Channel) receiveReplies(replies <-chan Reply) {
|
||||
if DEBUG_CHANNEL {
|
||||
log.Printf("%s ← %s : %s", channel, reply.Source(), reply)
|
||||
}
|
||||
for user := range channel.members {
|
||||
if user != reply.Source() {
|
||||
user.Replies() <- reply
|
||||
for client := range channel.members {
|
||||
if client != reply.Source() {
|
||||
client.replies <- reply
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func (channel *Channel) Nicks() []string {
|
||||
return channel.members.Nicks()
|
||||
}
|
||||
|
||||
func (channel *Channel) IsEmpty() bool {
|
||||
return len(channel.members) == 0
|
||||
@ -127,6 +83,16 @@ func (channel *Channel) GetUsers(replier Replier) {
|
||||
replier.Replies() <- NewNamesReply(channel)
|
||||
}
|
||||
|
||||
func (channel *Channel) Nicks() []string {
|
||||
nicks := make([]string, len(channel.members))
|
||||
i := 0
|
||||
for client := range channel.members {
|
||||
nicks[i] = client.Nick()
|
||||
i += 1
|
||||
}
|
||||
return nicks
|
||||
}
|
||||
|
||||
func (channel *Channel) Replies() chan<- Reply {
|
||||
return channel.replies
|
||||
}
|
||||
@ -143,20 +109,22 @@ func (channel *Channel) PublicId() string {
|
||||
return channel.name
|
||||
}
|
||||
|
||||
func (channel *Channel) Commands() chan<- ChannelCommand {
|
||||
return channel.commands
|
||||
}
|
||||
|
||||
func (channel *Channel) String() string {
|
||||
return channel.Id()
|
||||
}
|
||||
|
||||
func (channel *Channel) Join(user *User) {
|
||||
channel.members.Add(user)
|
||||
user.channels.Add(channel)
|
||||
channel.Replies() <- RplJoin(channel, user)
|
||||
channel.GetTopic(user)
|
||||
channel.GetUsers(user)
|
||||
func (channel *Channel) Join(client *Client) {
|
||||
channel.members[client] = true
|
||||
client.channels[channel] = true
|
||||
reply := RplJoin(channel, client)
|
||||
client.replies <- reply
|
||||
channel.replies <- reply
|
||||
channel.GetTopic(client)
|
||||
channel.GetUsers(client)
|
||||
}
|
||||
|
||||
func (channel *Channel) HasMember(client *Client) bool {
|
||||
return channel.members[client]
|
||||
}
|
||||
|
||||
//
|
||||
@ -166,58 +134,54 @@ func (channel *Channel) Join(user *User) {
|
||||
func (m *JoinCommand) HandleChannel(channel *Channel) {
|
||||
client := m.Client()
|
||||
if channel.key != m.channels[channel.name] {
|
||||
client.Replies() <- ErrBadChannelKey(channel)
|
||||
client.replies <- ErrBadChannelKey(channel)
|
||||
return
|
||||
}
|
||||
|
||||
channel.Join(client.user)
|
||||
channel.Join(client)
|
||||
}
|
||||
|
||||
func (m *PartCommand) HandleChannel(channel *Channel) {
|
||||
user := m.Client().user
|
||||
c := m.Client()
|
||||
|
||||
if !channel.members[user] {
|
||||
user.Replies() <- ErrNotOnChannel(channel)
|
||||
if !channel.HasMember(c) {
|
||||
c.replies <- ErrNotOnChannel(channel)
|
||||
return
|
||||
}
|
||||
|
||||
msg := m.message
|
||||
if msg == "" {
|
||||
msg = user.Nick()
|
||||
msg = c.Nick()
|
||||
}
|
||||
|
||||
channel.Replies() <- RplPart(channel, user, msg)
|
||||
channel.replies <- RplPart(channel, c, msg)
|
||||
|
||||
channel.members.Remove(user)
|
||||
user.channels.Remove(channel)
|
||||
delete(channel.members, c)
|
||||
delete(c.channels, channel)
|
||||
|
||||
if channel.IsEmpty() {
|
||||
if channel.IsEmpty() { // TODO persistent channels
|
||||
channel.server.DeleteChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TopicCommand) HandleChannel(channel *Channel) {
|
||||
user := m.User()
|
||||
client := m.Client()
|
||||
|
||||
if !channel.members[user] {
|
||||
user.Replies() <- ErrNotOnChannel(channel)
|
||||
if !channel.HasMember(client) {
|
||||
client.replies <- ErrNotOnChannel(channel)
|
||||
return
|
||||
}
|
||||
|
||||
if m.topic == "" {
|
||||
channel.GetTopic(user)
|
||||
channel.GetTopic(client)
|
||||
return
|
||||
}
|
||||
|
||||
channel.topic = m.topic
|
||||
|
||||
if channel.topic == "" {
|
||||
channel.Replies() <- RplNoTopic(channel)
|
||||
return
|
||||
}
|
||||
channel.Replies() <- RplTopic(channel)
|
||||
channel.GetTopic(channel)
|
||||
}
|
||||
|
||||
func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
|
||||
channel.Replies() <- RplPrivMsgChannel(channel, m.User(), m.message)
|
||||
channel.replies <- RplPrivMsgChannel(channel, m.Client(), m.message)
|
||||
}
|
||||
|
@ -8,22 +8,28 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG_CLIENT = true
|
||||
DEBUG_CLIENT = false
|
||||
)
|
||||
|
||||
type ClientCommand interface {
|
||||
Command
|
||||
HandleClient(*Client)
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
atime time.Time
|
||||
away bool
|
||||
channels ChannelSet
|
||||
commands chan<- ClientCommand
|
||||
conn net.Conn
|
||||
username string
|
||||
realname string
|
||||
hostname string
|
||||
nick string
|
||||
serverPass bool
|
||||
realname string
|
||||
registered bool
|
||||
away bool
|
||||
server *Server
|
||||
atime time.Time
|
||||
user *User
|
||||
replies chan<- Reply
|
||||
server *Server
|
||||
serverPass bool
|
||||
username string
|
||||
}
|
||||
|
||||
type ClientSet map[*Client]bool
|
||||
@ -31,17 +37,21 @@ type ClientSet map[*Client]bool
|
||||
func NewClient(server *Server, conn net.Conn) *Client {
|
||||
read := StringReadChan(conn)
|
||||
write := StringWriteChan(conn)
|
||||
commands := make(chan ClientCommand)
|
||||
replies := make(chan Reply)
|
||||
|
||||
client := &Client{
|
||||
channels: make(ChannelSet),
|
||||
commands: commands,
|
||||
conn: conn,
|
||||
hostname: conn.RemoteAddr().String(),
|
||||
server: server,
|
||||
hostname: LookupHostname(conn.RemoteAddr()),
|
||||
replies: replies,
|
||||
server: server,
|
||||
}
|
||||
|
||||
go client.readConn(read)
|
||||
go client.writeConn(write, replies)
|
||||
go client.receiveCommands(commands)
|
||||
|
||||
return client
|
||||
}
|
||||
@ -51,9 +61,9 @@ func (c *Client) readConn(recv <-chan string) {
|
||||
m, err := ParseCommand(str)
|
||||
if err != nil {
|
||||
if err == NotEnoughArgsError {
|
||||
c.Replies() <- ErrNeedMoreParams(c.server, str)
|
||||
c.replies <- ErrNeedMoreParams(c.server, str)
|
||||
} else {
|
||||
c.Replies() <- ErrUnknownCommand(c.server, str)
|
||||
c.replies <- ErrUnknownCommand(c.server, str)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -72,6 +82,15 @@ func (c *Client) writeConn(write chan<- string, replies <-chan Reply) {
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) receiveCommands(commands <-chan ClientCommand) {
|
||||
for command := range commands {
|
||||
if DEBUG_CLIENT {
|
||||
log.Printf("%s → %s : %s", command.Client(), client, command)
|
||||
}
|
||||
command.HandleClient(client)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Replies() chan<- Reply {
|
||||
return c.replies
|
||||
}
|
||||
@ -81,11 +100,7 @@ func (c *Client) Server() *Server {
|
||||
}
|
||||
|
||||
func (c *Client) Nick() string {
|
||||
if c.user != nil {
|
||||
return c.user.Nick()
|
||||
}
|
||||
|
||||
if c.nick != "" {
|
||||
if c.HasNick() {
|
||||
return c.nick
|
||||
}
|
||||
|
||||
@ -97,7 +112,7 @@ func (c *Client) UModeString() string {
|
||||
}
|
||||
|
||||
func (c *Client) HasNick() bool {
|
||||
return c.Nick() != ""
|
||||
return c.nick != ""
|
||||
}
|
||||
|
||||
func (c *Client) HasUsername() bool {
|
||||
@ -126,3 +141,11 @@ func (c *Client) String() string {
|
||||
func (c *Client) PublicId() string {
|
||||
return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id())
|
||||
}
|
||||
|
||||
//
|
||||
// commands
|
||||
//
|
||||
|
||||
func (m *PrivMsgCommand) HandleClient(client *Client) {
|
||||
client.replies <- RplPrivMsg(m.Client(), client, m.message)
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
|
||||
type Command interface {
|
||||
Client() *Client
|
||||
User() *User
|
||||
Source() Identifier
|
||||
Reply(Reply)
|
||||
HandleServer(*Server)
|
||||
@ -46,10 +45,6 @@ func (command *BaseCommand) Client() *Client {
|
||||
return command.client
|
||||
}
|
||||
|
||||
func (command *BaseCommand) User() *User {
|
||||
return command.Client().user
|
||||
}
|
||||
|
||||
func (command *BaseCommand) SetBase(c *Client) {
|
||||
*command = BaseCommand{c}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG_NET = true
|
||||
DEBUG_NET = false
|
||||
)
|
||||
|
||||
func readTrimmedLine(reader *bufio.Reader) (string, error) {
|
||||
@ -64,7 +64,7 @@ func LookupHostname(addr net.Addr) string {
|
||||
if err != nil {
|
||||
return addrStr
|
||||
}
|
||||
names, err := net.LookupAddr(ipaddr)
|
||||
names, err := net.LookupHost(ipaddr)
|
||||
if err != nil {
|
||||
return ipaddr
|
||||
}
|
||||
|
@ -1,158 +0,0 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG_NICKSERV = true
|
||||
)
|
||||
|
||||
type NickServCommand interface {
|
||||
HandleNickServ(*NickServ)
|
||||
Client() *Client
|
||||
SetBase(*Client)
|
||||
}
|
||||
|
||||
type NickServ struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
func NewNickServ(s *Server) Service {
|
||||
return NewService(new(NickServ), s, "NickServ")
|
||||
}
|
||||
|
||||
func (ns *NickServ) SetBase(base *BaseService) {
|
||||
ns.BaseService = *base
|
||||
}
|
||||
|
||||
func (ns *NickServ) Debug() bool {
|
||||
return DEBUG_NICKSERV
|
||||
}
|
||||
|
||||
var (
|
||||
parseNickServCommandFuncs = map[string]func([]string) (NickServCommand, error){
|
||||
"REGISTER": NewRegisterCommand,
|
||||
"IDENTIFY": NewIdentifyCommand,
|
||||
}
|
||||
)
|
||||
|
||||
//
|
||||
// commands
|
||||
//
|
||||
|
||||
func (ns *NickServ) HandlePrivMsg(m *PrivMsgCommand) {
|
||||
command, args := parseLine(m.message)
|
||||
constructor := parseNickServCommandFuncs[command]
|
||||
if constructor == nil {
|
||||
ns.Reply(m.Client(), "Unknown command.")
|
||||
return
|
||||
}
|
||||
|
||||
cmd, err := constructor(args)
|
||||
if err != nil {
|
||||
ns.Reply(m.Client(), "Not enough parameters.")
|
||||
return
|
||||
}
|
||||
|
||||
cmd.SetBase(m.Client())
|
||||
if ns.Debug() {
|
||||
log.Printf("%s ← %s %s", ns, cmd.Client(), cmd)
|
||||
}
|
||||
|
||||
cmd.HandleNickServ(ns)
|
||||
}
|
||||
|
||||
//
|
||||
// sub-commands
|
||||
//
|
||||
|
||||
type RegisterCommand struct {
|
||||
BaseCommand
|
||||
password string
|
||||
email string
|
||||
}
|
||||
|
||||
func (m *RegisterCommand) String() string {
|
||||
return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password)
|
||||
}
|
||||
|
||||
func NewRegisterCommand(args []string) (NickServCommand, error) {
|
||||
if len(args) == 0 {
|
||||
return nil, NotEnoughArgsError
|
||||
}
|
||||
|
||||
cmd := &RegisterCommand{
|
||||
BaseCommand: BaseCommand{},
|
||||
password: args[0],
|
||||
}
|
||||
if len(args) > 1 {
|
||||
cmd.email = args[1]
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (m *RegisterCommand) HandleNickServ(ns *NickServ) {
|
||||
client := m.Client()
|
||||
|
||||
if client.user != nil {
|
||||
ns.Reply(client, "You are already registered.")
|
||||
return
|
||||
}
|
||||
|
||||
if ns.server.users[client.nick] != nil {
|
||||
ns.Reply(client, "That nick is already registered.")
|
||||
return
|
||||
}
|
||||
|
||||
user := NewUser(client.nick, ns.server)
|
||||
user.SetPassword(m.password)
|
||||
Save(ns.server.db, user)
|
||||
ns.Reply(client, "You have registered.")
|
||||
|
||||
if !user.Login(client, client.nick, m.password) {
|
||||
ns.Reply(client, "Login failed.")
|
||||
return
|
||||
}
|
||||
ns.Reply(client, "Logged in.")
|
||||
}
|
||||
|
||||
type IdentifyCommand struct {
|
||||
BaseCommand
|
||||
password string
|
||||
}
|
||||
|
||||
func (m *IdentifyCommand) String() string {
|
||||
return fmt.Sprintf("IDENTIFY(password=%s)", m.password)
|
||||
}
|
||||
|
||||
func NewIdentifyCommand(args []string) (NickServCommand, error) {
|
||||
if len(args) == 0 {
|
||||
return nil, NotEnoughArgsError
|
||||
}
|
||||
|
||||
return &IdentifyCommand{
|
||||
BaseCommand: BaseCommand{},
|
||||
password: args[0],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *IdentifyCommand) HandleNickServ(ns *NickServ) {
|
||||
client := m.Client()
|
||||
if client.user != nil {
|
||||
ns.Reply(client, "That nick is already registered.")
|
||||
return
|
||||
}
|
||||
|
||||
user := ns.server.users[client.nick]
|
||||
if user == nil {
|
||||
ns.Reply(client, "No such nick.")
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Login(client, client.nick, m.password) {
|
||||
ns.Reply(client, "Login failed.")
|
||||
}
|
||||
ns.Reply(client, "Logged in.")
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
//"fmt"
|
||||
"bufio"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RowId uint64
|
||||
|
||||
type Queryable interface {
|
||||
Exec(string, ...interface{}) (sql.Result, error)
|
||||
Query(string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRow(string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
type Savable interface {
|
||||
Save(q Queryable) bool
|
||||
}
|
||||
|
||||
type Loadable interface {
|
||||
Load(q Queryable) bool
|
||||
}
|
||||
|
||||
//
|
||||
// general
|
||||
//
|
||||
|
||||
func NewDatabase() (db *sql.DB) {
|
||||
db, err := sql.Open("sqlite3", "ergonomadic.db")
|
||||
if err != nil {
|
||||
log.Fatalln("cannot open database")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readLines(filename string) <-chan string {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
reader := bufio.NewReader(file)
|
||||
lines := make(chan string)
|
||||
go func(lines chan<- string) {
|
||||
defer file.Close()
|
||||
defer close(lines)
|
||||
for {
|
||||
line, err := reader.ReadString(';')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
lines <- line
|
||||
}
|
||||
}(lines)
|
||||
return lines
|
||||
}
|
||||
|
||||
func ExecSqlFile(db *sql.DB, filename string) {
|
||||
Transact(db, func(q Queryable) bool {
|
||||
for line := range readLines(filepath.Join("sql", filename)) {
|
||||
log.Println(line)
|
||||
_, err := q.Exec(line)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func Transact(db *sql.DB, txf func(Queryable) bool) {
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
if txf(tx) {
|
||||
tx.Commit()
|
||||
} else {
|
||||
tx.Rollback()
|
||||
}
|
||||
}
|
||||
|
||||
func Save(db *sql.DB, s Savable) {
|
||||
Transact(db, s.Save)
|
||||
}
|
||||
|
||||
func Load(db *sql.DB, l Loadable) {
|
||||
Transact(db, l.Load)
|
||||
}
|
||||
|
||||
//
|
||||
// general purpose sql
|
||||
//
|
||||
|
||||
func findId(q Queryable, sql string, args ...interface{}) (rowId RowId, err error) {
|
||||
row := q.QueryRow(sql, args...)
|
||||
err = row.Scan(&rowId)
|
||||
return
|
||||
}
|
||||
|
||||
func countRows(q Queryable, sql string, args ...interface{}) (count uint, err error) {
|
||||
row := q.QueryRow(sql, args...)
|
||||
err = row.Scan(&count)
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// data
|
||||
//
|
||||
|
||||
type UserRow struct {
|
||||
id RowId
|
||||
nick string
|
||||
hash []byte
|
||||
}
|
||||
|
||||
type ChannelRow struct {
|
||||
id RowId
|
||||
name string
|
||||
}
|
||||
|
||||
// user
|
||||
|
||||
func FindAllUsers(q Queryable) (urs []*UserRow, err error) {
|
||||
var rows *sql.Rows
|
||||
rows, err = q.Query("SELECT id, nick, hash FROM user")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
urs = make([]*UserRow, 0)
|
||||
for rows.Next() {
|
||||
ur := &UserRow{}
|
||||
err = rows.Scan(&(ur.id), &(ur.nick), &(ur.hash))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
urs = append(urs, ur)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FindUserByNick(q Queryable, nick string) (ur *UserRow, err error) {
|
||||
ur = &UserRow{}
|
||||
row := q.QueryRow("SELECT id, nick, hash FROM user LIMIT 1 WHERE nick = ?",
|
||||
nick)
|
||||
err = row.Scan(&(ur.id), &(ur.nick), &(ur.hash))
|
||||
return
|
||||
}
|
||||
|
||||
func FindUserIdByNick(q Queryable, nick string) (RowId, error) {
|
||||
return findId(q, "SELECT id FROM user WHERE nick = ?", nick)
|
||||
}
|
||||
|
||||
func FindChannelByName(q Queryable, name string) (cr *ChannelRow) {
|
||||
cr = new(ChannelRow)
|
||||
row := q.QueryRow("SELECT id, name FROM channel LIMIT 1 WHERE name = ?", name)
|
||||
err := row.Scan(&(cr.id), &(cr.name))
|
||||
if err != nil {
|
||||
cr = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func InsertUser(q Queryable, row *UserRow) (err error) {
|
||||
_, err = q.Exec("INSERT INTO user (nick, hash) VALUES (?, ?)",
|
||||
row.nick, row.hash)
|
||||
return
|
||||
}
|
||||
|
||||
func UpdateUser(q Queryable, row *UserRow) (err error) {
|
||||
_, err = q.Exec("UPDATE user SET nick = ?, hash = ? WHERE id = ?",
|
||||
row.nick, row.hash, row.id)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteUser(q Queryable, id RowId) (err error) {
|
||||
_, err = q.Exec("DELETE FROM user WHERE id = ?", id)
|
||||
return
|
||||
}
|
||||
|
||||
// user-channel
|
||||
|
||||
func DeleteAllUserChannels(q Queryable, rowId RowId) (err error) {
|
||||
_, err = q.Exec("DELETE FROM user_channel WHERE user_id = ?", rowId)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteOtherUserChannels(q Queryable, userId RowId, channelIds []RowId) (err error) {
|
||||
_, err = q.Exec(`DELETE FROM user_channel WHERE
|
||||
user_id = ? AND channel_id NOT IN ?`, userId, channelIds)
|
||||
return
|
||||
}
|
||||
|
||||
func InsertUserChannels(q Queryable, userId RowId, channelIds []RowId) (err error) {
|
||||
ins := "INSERT OR IGNORE INTO user_channel (user_id, channel_id) VALUES "
|
||||
vals := strings.Repeat("(?, ?), ", len(channelIds))
|
||||
vals = vals[0 : len(vals)-2]
|
||||
args := make([]RowId, 2*len(channelIds))
|
||||
for i, channelId := range channelIds {
|
||||
args[i] = userId
|
||||
args[i+1] = channelId
|
||||
}
|
||||
_, err = q.Exec(ins+vals, args)
|
||||
return
|
||||
}
|
||||
|
||||
// channel
|
||||
|
||||
func FindChannelIdByName(q Queryable, name string) (RowId, error) {
|
||||
return findId(q, "SELECT id FROM channel WHERE name = ?", name)
|
||||
}
|
||||
|
||||
func findChannels(q Queryable, where string, args ...interface{}) (crs []*ChannelRow, err error) {
|
||||
count, err := countRows(q, "SELECT COUNT(id) FROM channel "+where, args...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rows, err := q.Query("SELECT id, name FROM channel "+where, args...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crs = make([]*ChannelRow, count)
|
||||
var i = 0
|
||||
for rows.Next() {
|
||||
cr := &ChannelRow{}
|
||||
err = rows.Scan(&(cr.id), &(cr.name))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crs[i] = cr
|
||||
i++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FindChannelsForUser(q Queryable, userId RowId) (crs []*ChannelRow, err error) {
|
||||
crs, err = findChannels(q,
|
||||
"WHERE id IN (SELECT channel_id from user_channel WHERE user_id = ?)", userId)
|
||||
return
|
||||
}
|
||||
|
||||
func FindAllChannels(q Queryable) (crs []*ChannelRow, err error) {
|
||||
crs, err = findChannels(q, "")
|
||||
return
|
||||
}
|
||||
|
||||
func InsertChannel(q Queryable, channel *Channel) (err error) {
|
||||
_, err = q.Exec("INSERT INTO channel (name) VALUES (?)", channel.name)
|
||||
return
|
||||
}
|
||||
|
||||
func UpdateChannel(q Queryable, channel *Channel) (err error) {
|
||||
_, err = q.Exec("UPDATE channel SET name = ? WHERE id = ?",
|
||||
channel.name, *(channel.id))
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteChannel(q Queryable, channel *Channel) (err error) {
|
||||
_, err = q.Exec("DELETE FROM channel WHERE id = ?", *(channel.id))
|
||||
return
|
||||
}
|
@ -93,6 +93,7 @@ func NewNamesReply(channel *Channel) Reply {
|
||||
BaseReply: &BaseReply{
|
||||
source: channel,
|
||||
},
|
||||
channel: channel,
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,12 +143,12 @@ func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Repl
|
||||
return NewStringReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message)
|
||||
}
|
||||
|
||||
func RplJoin(channel *Channel, user *User) Reply {
|
||||
return NewStringReply(user, RPL_JOIN, channel.name)
|
||||
func RplJoin(channel *Channel, client *Client) Reply {
|
||||
return NewStringReply(client, RPL_JOIN, channel.name)
|
||||
}
|
||||
|
||||
func RplPart(channel *Channel, user *User, message string) Reply {
|
||||
return NewStringReply(user, RPL_PART, "%s :%s", channel.name, message)
|
||||
func RplPart(channel *Channel, client *Client, message string) Reply {
|
||||
return NewStringReply(client, RPL_PART, "%s :%s", channel.name, message)
|
||||
}
|
||||
|
||||
func RplPong(server *Server) Reply {
|
||||
|
@ -2,7 +2,6 @@ package irc
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"database/sql"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
@ -13,19 +12,16 @@ const (
|
||||
)
|
||||
|
||||
type ChannelNameMap map[string]*Channel
|
||||
type UserNameMap map[string]*User
|
||||
type ServiceNameMap map[string]Service
|
||||
type ClientNameMap map[string]*Client
|
||||
|
||||
type Server struct {
|
||||
hostname string
|
||||
channels ChannelNameMap
|
||||
commands chan<- Command
|
||||
ctime time.Time
|
||||
hostname string
|
||||
name string
|
||||
password []byte
|
||||
users UserNameMap
|
||||
channels ChannelNameMap
|
||||
services ServiceNameMap
|
||||
commands chan<- Command
|
||||
db *sql.DB
|
||||
clients ClientNameMap
|
||||
}
|
||||
|
||||
func NewServer(name string) *Server {
|
||||
@ -34,43 +30,13 @@ func NewServer(name string) *Server {
|
||||
ctime: time.Now(),
|
||||
name: name,
|
||||
commands: commands,
|
||||
users: make(UserNameMap),
|
||||
clients: make(ClientNameMap),
|
||||
channels: make(ChannelNameMap),
|
||||
services: make(ServiceNameMap),
|
||||
db: NewDatabase(),
|
||||
}
|
||||
go server.receiveCommands(commands)
|
||||
NewNickServ(server)
|
||||
Load(server.db, server)
|
||||
return server
|
||||
}
|
||||
|
||||
func (server *Server) Load(q Queryable) bool {
|
||||
crs, err := FindAllChannels(q)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
for _, cr := range crs {
|
||||
channel := server.GetOrMakeChannel(cr.name)
|
||||
channel.id = &(cr.id)
|
||||
}
|
||||
|
||||
urs, err := FindAllUsers(q)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
for _, ur := range urs {
|
||||
user := NewUser(ur.nick, server)
|
||||
user.SetHash(ur.hash)
|
||||
if !user.Load(q) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (server *Server) receiveCommands(commands <-chan Command) {
|
||||
for command := range commands {
|
||||
if DEBUG_SERVER {
|
||||
@ -113,16 +79,16 @@ func (s *Server) GetOrMakeChannel(name string) *Channel {
|
||||
}
|
||||
|
||||
// Send a message to clients of channels fromClient is a member.
|
||||
func (s *Server) InterestedUsers(fromUser *User) UserSet {
|
||||
users := make(UserSet)
|
||||
users.Add(fromUser)
|
||||
for channel := range fromUser.channels {
|
||||
for user := range channel.members {
|
||||
users.Add(user)
|
||||
func (s *Server) interestedClients(fromClient *Client) ClientSet {
|
||||
clients := make(ClientSet)
|
||||
clients[fromClient] = true
|
||||
for channel := range fromClient.channels {
|
||||
for client := range channel.members {
|
||||
clients[client] = true
|
||||
}
|
||||
}
|
||||
|
||||
return users
|
||||
return clients
|
||||
}
|
||||
|
||||
// server functionality
|
||||
@ -164,9 +130,6 @@ func (s *Server) Nick() string {
|
||||
|
||||
func (s *Server) DeleteChannel(channel *Channel) {
|
||||
delete(s.channels, channel.name)
|
||||
if err := DeleteChannel(s.db, channel); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -198,32 +161,30 @@ func (m *PassCommand) HandleServer(s *Server) {
|
||||
|
||||
func (m *NickCommand) HandleServer(s *Server) {
|
||||
c := m.Client()
|
||||
if c.user == nil {
|
||||
c.Replies() <- RplNick(c, m.nickname)
|
||||
c.nick = m.nickname
|
||||
s.tryRegister(c)
|
||||
|
||||
if s.clients[m.nickname] != nil {
|
||||
c.replies <- ErrNickNameInUse(s, m.nickname)
|
||||
return
|
||||
}
|
||||
|
||||
user := c.user
|
||||
if s.users[m.nickname] != nil {
|
||||
user.Replies() <- ErrNickNameInUse(s, m.nickname)
|
||||
return
|
||||
reply := RplNick(c, m.nickname)
|
||||
for iclient := range s.interestedClients(c) {
|
||||
iclient.replies <- reply
|
||||
}
|
||||
|
||||
delete(s.users, user.nick)
|
||||
s.users[m.nickname] = user
|
||||
reply := RplNick(user, m.nickname)
|
||||
for iuser := range s.InterestedUsers(user) {
|
||||
iuser.Replies() <- reply
|
||||
if c.HasNick() {
|
||||
delete(s.clients, c.nick)
|
||||
}
|
||||
user.nick = m.nickname
|
||||
s.clients[m.nickname] = c
|
||||
c.nick = m.nickname
|
||||
|
||||
s.tryRegister(c)
|
||||
}
|
||||
|
||||
func (m *UserMsgCommand) HandleServer(s *Server) {
|
||||
c := m.Client()
|
||||
if c.username != "" {
|
||||
c.Replies() <- ErrAlreadyRegistered(s)
|
||||
if c.registered {
|
||||
c.replies <- ErrAlreadyRegistered(s)
|
||||
return
|
||||
}
|
||||
|
||||
@ -234,108 +195,65 @@ func (m *UserMsgCommand) HandleServer(s *Server) {
|
||||
func (m *QuitCommand) HandleServer(s *Server) {
|
||||
c := m.Client()
|
||||
|
||||
user := c.user
|
||||
if user != nil {
|
||||
reply := RplQuit(c, m.message)
|
||||
for user := range s.InterestedUsers(c.user) {
|
||||
user.Replies() <- reply
|
||||
}
|
||||
reply := RplQuit(c, m.message)
|
||||
for client := range s.interestedClients(c) {
|
||||
client.replies <- reply
|
||||
}
|
||||
c.conn.Close()
|
||||
if user == nil {
|
||||
return
|
||||
cmd := &PartCommand{
|
||||
BaseCommand: BaseCommand{c},
|
||||
}
|
||||
|
||||
user.LogoutClient(c)
|
||||
if !user.HasClients() {
|
||||
cmd := &PartCommand{
|
||||
BaseCommand: BaseCommand{c},
|
||||
}
|
||||
for channel := range user.channels {
|
||||
channel.Commands() <- cmd
|
||||
}
|
||||
for channel := range c.channels {
|
||||
channel.commands <- cmd
|
||||
}
|
||||
}
|
||||
|
||||
func (m *JoinCommand) HandleServer(s *Server) {
|
||||
c := m.Client()
|
||||
|
||||
if c.user == nil {
|
||||
c.Replies() <- ErrNoPrivileges(s)
|
||||
return
|
||||
}
|
||||
|
||||
if m.zero {
|
||||
cmd := &PartCommand{
|
||||
BaseCommand: BaseCommand{c},
|
||||
}
|
||||
for channel := range c.user.channels {
|
||||
channel.Commands() <- cmd
|
||||
for channel := range c.channels {
|
||||
channel.commands <- cmd
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for name := range m.channels {
|
||||
s.GetOrMakeChannel(name).Commands() <- m
|
||||
s.GetOrMakeChannel(name).commands <- m
|
||||
}
|
||||
}
|
||||
|
||||
func (m *PartCommand) HandleServer(s *Server) {
|
||||
user := m.User()
|
||||
|
||||
if user == nil {
|
||||
m.Client().Replies() <- ErrNoPrivileges(s)
|
||||
return
|
||||
}
|
||||
|
||||
for _, chname := range m.channels {
|
||||
channel := s.channels[chname]
|
||||
|
||||
if channel == nil {
|
||||
user.Replies() <- ErrNoSuchChannel(s, channel.name)
|
||||
m.Client().replies <- ErrNoSuchChannel(s, channel.name)
|
||||
continue
|
||||
}
|
||||
|
||||
channel.Commands() <- m
|
||||
channel.commands <- m
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TopicCommand) HandleServer(s *Server) {
|
||||
user := m.User()
|
||||
|
||||
// Hide all channels from logged-out clients.
|
||||
if user == nil {
|
||||
m.Client().Replies() <- ErrNoPrivileges(s)
|
||||
return
|
||||
}
|
||||
|
||||
channel := s.channels[m.channel]
|
||||
if channel == nil {
|
||||
m.Client().Replies() <- ErrNoSuchChannel(s, m.channel)
|
||||
m.Client().replies <- ErrNoSuchChannel(s, m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
channel.Commands() <- m
|
||||
channel.commands <- m
|
||||
}
|
||||
|
||||
func (m *PrivMsgCommand) HandleServer(s *Server) {
|
||||
service := s.services[m.target]
|
||||
if service != nil {
|
||||
service.Commands() <- m
|
||||
return
|
||||
}
|
||||
|
||||
user := m.User()
|
||||
// Hide all users from logged-out clients.
|
||||
if user == nil {
|
||||
m.Client().Replies() <- ErrNoPrivileges(s)
|
||||
return
|
||||
}
|
||||
|
||||
if m.TargetIsChannel() {
|
||||
channel := s.channels[m.target]
|
||||
if channel == nil {
|
||||
m.Client().Replies() <- ErrNoSuchChannel(s, m.target)
|
||||
m.Client().replies <- ErrNoSuchChannel(s, m.target)
|
||||
return
|
||||
}
|
||||
|
||||
@ -343,9 +261,9 @@ func (m *PrivMsgCommand) HandleServer(s *Server) {
|
||||
return
|
||||
}
|
||||
|
||||
target := s.users[m.target]
|
||||
target := s.clients[m.target]
|
||||
if target == nil {
|
||||
m.Client().Replies() <- ErrNoSuchNick(s, m.target)
|
||||
m.Client().replies <- ErrNoSuchNick(s, m.target)
|
||||
return
|
||||
}
|
||||
|
||||
@ -353,5 +271,5 @@ func (m *PrivMsgCommand) HandleServer(s *Server) {
|
||||
}
|
||||
|
||||
func (m *ModeCommand) HandleServer(s *Server) {
|
||||
m.Client().Replies() <- RplUModeIs(s, m.Client())
|
||||
m.Client().replies <- RplUModeIs(s, m.Client())
|
||||
}
|
||||
|
@ -1,83 +0,0 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type ServiceCommand interface {
|
||||
Command
|
||||
HandleService(Service)
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
Identifier
|
||||
Commands() chan<- ServiceCommand
|
||||
HandlePrivMsg(*PrivMsgCommand)
|
||||
Debug() bool
|
||||
}
|
||||
|
||||
type EditableService interface {
|
||||
Service
|
||||
SetBase(*BaseService)
|
||||
}
|
||||
|
||||
type BaseService struct {
|
||||
server *Server
|
||||
name string
|
||||
commands chan<- ServiceCommand
|
||||
}
|
||||
|
||||
func NewService(service EditableService, s *Server, name string) Service {
|
||||
commands := make(chan ServiceCommand)
|
||||
base := &BaseService{
|
||||
server: s,
|
||||
name: name,
|
||||
commands: commands,
|
||||
}
|
||||
go receiveCommands(service, commands)
|
||||
service.SetBase(base)
|
||||
s.services[service.Nick()] = service
|
||||
return service
|
||||
}
|
||||
|
||||
func receiveCommands(service Service, commands <-chan ServiceCommand) {
|
||||
for command := range commands {
|
||||
if service.Debug() {
|
||||
log.Printf("%s ← %s %s", service.Id(), command.Client(), command)
|
||||
}
|
||||
command.HandleService(service)
|
||||
}
|
||||
}
|
||||
|
||||
func (service *BaseService) Id() string {
|
||||
return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name)
|
||||
}
|
||||
|
||||
func (service *BaseService) String() string {
|
||||
return service.Id()
|
||||
}
|
||||
|
||||
func (service *BaseService) PublicId() string {
|
||||
return service.Id()
|
||||
}
|
||||
|
||||
func (service *BaseService) Nick() string {
|
||||
return service.name
|
||||
}
|
||||
|
||||
func (service *BaseService) Reply(client *Client, message string) {
|
||||
client.Replies() <- RplPrivMsg(service, client, message)
|
||||
}
|
||||
|
||||
func (service *BaseService) Commands() chan<- ServiceCommand {
|
||||
return service.commands
|
||||
}
|
||||
|
||||
//
|
||||
// commands
|
||||
//
|
||||
|
||||
func (m *PrivMsgCommand) HandleService(service Service) {
|
||||
service.HandlePrivMsg(m)
|
||||
}
|
228
src/irc/user.go
228
src/irc/user.go
@ -1,228 +0,0 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG_USER = true
|
||||
)
|
||||
|
||||
type UserCommand interface {
|
||||
Command
|
||||
HandleUser(*User)
|
||||
}
|
||||
|
||||
type User struct {
|
||||
id RowId
|
||||
nick string
|
||||
hash []byte
|
||||
server *Server
|
||||
clients ClientSet
|
||||
channels ChannelSet
|
||||
commands chan<- UserCommand
|
||||
replies chan<- Reply
|
||||
}
|
||||
|
||||
type UserSet map[*User]bool
|
||||
|
||||
func (set UserSet) Add(user *User) {
|
||||
set[user] = true
|
||||
}
|
||||
|
||||
func (set UserSet) Remove(user *User) {
|
||||
delete(set, user)
|
||||
}
|
||||
|
||||
func (set UserSet) Nicks() []string {
|
||||
nicks := make([]string, len(set))
|
||||
i := 0
|
||||
for member := range set {
|
||||
nicks[i] = member.Nick()
|
||||
i++
|
||||
}
|
||||
return nicks
|
||||
}
|
||||
|
||||
func NewUser(nick string, server *Server) *User {
|
||||
commands := make(chan UserCommand)
|
||||
replies := make(chan Reply)
|
||||
user := &User{
|
||||
nick: nick,
|
||||
server: server,
|
||||
clients: make(ClientSet),
|
||||
channels: make(ChannelSet),
|
||||
replies: replies,
|
||||
}
|
||||
|
||||
go user.receiveCommands(commands)
|
||||
go user.receiveReplies(replies)
|
||||
server.users[nick] = user
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func (user *User) Row() *UserRow {
|
||||
return &UserRow{user.id, user.nick, user.hash}
|
||||
}
|
||||
|
||||
func (user *User) Create(q Queryable) bool {
|
||||
var err error
|
||||
if err := InsertUser(q, user.Row()); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
user.id, err = FindUserIdByNick(q, user.nick)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) Save(q Queryable) bool {
|
||||
if err := UpdateUser(q, user.Row()); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
|
||||
channelIds := user.channels.Ids()
|
||||
if len(channelIds) == 0 {
|
||||
if err := DeleteAllUserChannels(q, user.id); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if err := DeleteOtherUserChannels(q, user.id, channelIds); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
if err := InsertUserChannels(q, user.id, channelIds); err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) Delete(q Queryable) bool {
|
||||
err := DeleteUser(q, user.id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) Load(q Queryable) bool {
|
||||
crs, err := FindChannelsForUser(q, user.id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
for _, cr := range crs {
|
||||
user.server.GetOrMakeChannel(cr.name).Join(user)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) SetPassword(password string) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
user.SetHash(hash)
|
||||
}
|
||||
|
||||
func (user *User) SetHash(hash []byte) {
|
||||
user.hash = hash
|
||||
}
|
||||
|
||||
func (user *User) receiveCommands(commands <-chan UserCommand) {
|
||||
for command := range commands {
|
||||
if DEBUG_USER {
|
||||
log.Printf("%s → %s : %s", command.Client(), user, command)
|
||||
}
|
||||
command.HandleUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
// Distribute replies to clients.
|
||||
func (user *User) receiveReplies(replies <-chan Reply) {
|
||||
for reply := range replies {
|
||||
if DEBUG_USER {
|
||||
log.Printf("%s ← %s : %s", user, reply.Source(), reply)
|
||||
}
|
||||
for client := range user.clients {
|
||||
client.Replies() <- reply
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identifier
|
||||
|
||||
func (user *User) Id() string {
|
||||
return fmt.Sprintf("%s!%s@%s", user.nick, user.nick, user.server.Id())
|
||||
}
|
||||
|
||||
func (user *User) PublicId() string {
|
||||
return user.Id()
|
||||
}
|
||||
|
||||
func (user *User) Nick() string {
|
||||
return user.nick
|
||||
}
|
||||
|
||||
func (user *User) String() string {
|
||||
return user.Id()
|
||||
}
|
||||
|
||||
func (user *User) Login(c *Client, nick string, password string) bool {
|
||||
if nick != c.nick {
|
||||
return false
|
||||
}
|
||||
|
||||
if user.hash == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err := bcrypt.CompareHashAndPassword(user.hash, []byte(password))
|
||||
if err != nil {
|
||||
c.Replies() <- ErrNoPrivileges(user.server)
|
||||
return false
|
||||
}
|
||||
|
||||
user.clients[c] = true
|
||||
c.user = user
|
||||
for channel := range user.channels {
|
||||
channel.GetTopic(c)
|
||||
channel.GetUsers(c)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) LogoutClient(c *Client) bool {
|
||||
if user.clients[c] {
|
||||
delete(user.clients, c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (user *User) HasClients() bool {
|
||||
return len(user.clients) > 0
|
||||
}
|
||||
|
||||
func (user *User) Replies() chan<- Reply {
|
||||
return user.replies
|
||||
}
|
||||
|
||||
//
|
||||
// commands
|
||||
//
|
||||
|
||||
func (m *PrivMsgCommand) HandleUser(user *User) {
|
||||
user.Replies() <- RplPrivMsg(m.Client(), user, m.message)
|
||||
}
|
Loading…
Reference in New Issue
Block a user