2019-08-19 23:30:59 +00:00
package sircd
2019-08-21 08:15:45 +00:00
import "github.com/sirupsen/logrus"
import "github.com/spf13/viper"
import "net"
2019-08-19 23:30:59 +00:00
2019-08-21 08:15:45 +00:00
type ircd struct {
2019-08-20 02:15:56 +00:00
Running bool
2019-08-21 06:15:12 +00:00
serverName string
2019-08-20 02:15:56 +00:00
log * logrus . Logger
netName string
ircPort uint16
httpPort uint16
ircListener net . Listener
ircClients map [ * ircClient ] bool
newClients chan * ircClient
deadClients chan * ircClient
messageQueue chan * ircMessage
2019-08-21 08:18:10 +00:00
c * viper . Viper
2019-08-19 23:30:59 +00:00
}
const (
CONN_HOST = "localhost"
CONN_PORT = "6667"
CONN_TYPE = "tcp"
)
2019-08-21 08:15:45 +00:00
func New ( config * viper . Viper ) * ircd {
s := new ( ircd )
2019-08-20 00:50:40 +00:00
s . Running = true
2019-08-20 02:15:56 +00:00
s . ircClients = make ( map [ * ircClient ] bool )
2019-08-21 08:18:10 +00:00
s . c = config
s . serverName = s . c . GetString ( "myhostname" )
2019-08-19 23:30:59 +00:00
return s
}
2019-08-21 08:15:45 +00:00
func ( s * ircd ) SetLogger ( logger * logrus . Logger ) {
2019-08-21 06:15:12 +00:00
s . log = logger
}
2019-08-21 08:15:45 +00:00
func ( s * ircd ) SetServerName ( name string ) {
2019-08-21 06:15:12 +00:00
s . serverName = name
2019-08-19 23:56:27 +00:00
}
2019-08-21 08:15:45 +00:00
func ( s * ircd ) Start ( ) {
2019-08-21 08:31:57 +00:00
s . log . Infof ( "sircd version %s (%s) built %s by %s starting." , s . c . GetString ( "version" ) , s . c . GetString ( "buildarch" ) , s . c . GetString ( "buildtime" ) , s . c . GetString ( "builduser" ) )
2019-08-20 02:15:56 +00:00
s . newClients = make ( chan * ircClient , 128 )
s . deadClients = make ( chan * ircClient , 128 )
s . messageQueue = make ( chan * ircMessage , 128 )
2019-08-20 00:50:40 +00:00
var err error
2019-08-19 23:30:59 +00:00
s . ircListener , err = net . Listen ( CONN_TYPE , CONN_HOST + ":" + CONN_PORT )
2019-08-20 00:50:40 +00:00
if err != nil {
2019-08-20 02:15:56 +00:00
s . log . Fatalln ( "Error listening:" , err . Error ( ) )
2019-08-20 00:50:40 +00:00
}
2019-08-21 08:15:45 +00:00
s . log . Println ( "Listening for irc proto on " + CONN_HOST + ":" + CONN_PORT )
2019-08-19 23:30:59 +00:00
2019-08-20 02:15:56 +00:00
go func ( ) {
2019-08-19 23:30:59 +00:00
conn , err := s . ircListener . Accept ( )
if err != nil {
2019-08-20 02:15:56 +00:00
s . log . Panicf ( "Error accepting: " , err . Error ( ) )
2019-08-19 23:30:59 +00:00
}
2019-08-21 06:15:12 +00:00
s . newClients <- newIrcClient ( conn , s . log , s . messageQueue , s )
2019-08-20 02:15:56 +00:00
} ( )
2019-08-20 00:50:40 +00:00
2019-08-21 08:18:10 +00:00
// FIXME have this do 'go s.handlemessages()' and process an input channel
// of messages from all clients in its own goroutine, and then call
// directly into the main loop here and only do client i/o in this
// goroutine
go s . processMessages ( )
2019-08-21 08:15:45 +00:00
s . mainLoop ( )
}
func ( s * ircd ) processMessages ( ) {
2019-08-21 08:18:10 +00:00
for {
message := <- s . messageQueue
s . processIRCMessage ( message )
}
2019-08-19 23:30:59 +00:00
}
2019-08-21 08:15:45 +00:00
func ( s * ircd ) mainLoop ( ) {
2019-08-20 02:15:56 +00:00
for {
select {
case client := <- s . newClients :
s . ircClients [ client ] = true
s . log . Println ( "new irc client: %s" , client . Id )
go func ( ) {
buf := make ( [ ] byte , 1024 * 1024 )
for {
nbyte , err := client . conn . Read ( buf )
if err != nil {
2019-08-21 06:15:12 +00:00
//this will surface it in the deadClients channel
2019-08-21 08:18:10 +00:00
//reader below
2019-08-21 06:15:12 +00:00
client . Kill ( )
2019-08-20 02:15:56 +00:00
break
} else {
fragment := make ( [ ] byte , nbyte )
copy ( fragment , buf [ : nbyte ] )
// this will populate the message channel
client . AppendInputBuffer ( fragment )
}
}
} ( )
case deadClient := <- s . deadClients :
delete ( s . ircClients , deadClient )
2019-08-21 06:15:12 +00:00
deadClient . CleanupAndClose ( )
2019-08-20 02:15:56 +00:00
}
}
2019-08-19 23:30:59 +00:00
}