2022-01-18 17:26:37 +00:00
package server
import (
"context"
2022-02-05 09:54:41 +00:00
"fmt"
2022-01-25 16:27:58 +00:00
"github.com/ChronosX88/yans/internal/models"
2022-01-18 17:26:37 +00:00
"github.com/ChronosX88/yans/internal/protocol"
"io"
"log"
"net"
"net/textproto"
)
2022-01-18 17:43:05 +00:00
type SessionMode int
const (
SessionModeTransit = iota
SessionModeReader
)
2022-01-18 17:26:37 +00:00
type Session struct {
ctx context . Context
capabilities protocol . Capabilities
conn net . Conn
tconn * textproto . Conn
id string
closed chan <- bool
h * Handler
2022-01-25 16:27:58 +00:00
currentGroup * models . Group
2022-01-18 17:43:05 +00:00
mode SessionMode
2022-01-18 17:26:37 +00:00
}
func NewSession ( ctx context . Context , conn net . Conn , caps protocol . Capabilities , id string , closed chan <- bool , handler * Handler ) ( * Session , error ) {
var err error
defer func ( ) {
if err != nil {
conn . Close ( )
close ( closed )
}
} ( )
tconn := textproto . NewConn ( conn )
s := & Session {
ctx : ctx ,
conn : conn ,
tconn : tconn ,
capabilities : caps ,
id : id ,
closed : closed ,
h : handler ,
2022-01-18 17:43:05 +00:00
mode : SessionModeTransit ,
2022-01-18 17:26:37 +00:00
}
go s . loop ( )
return s , nil
}
func ( s * Session ) loop ( ) {
defer func ( ) {
close ( s . closed )
} ( )
2022-02-05 09:54:41 +00:00
err := s . tconn . PrintfLine ( protocol . NNTPResponse { Code : 201 , Message : "YANS NNTP Service Ready, posting prohibited" } . String ( ) ) // by default access mode is read-only
2022-01-18 17:26:37 +00:00
if err != nil {
s . conn . Close ( )
return
}
for {
select {
case <- s . ctx . Done ( ) :
break
default :
{
2022-01-19 21:44:27 +00:00
id := s . tconn . Next ( )
s . tconn . StartRequest ( id )
2022-01-18 17:26:37 +00:00
message , err := s . tconn . ReadLine ( )
if err != nil {
if err == io . EOF || err . ( * net . OpError ) . Unwrap ( ) == net . ErrClosed {
log . Printf ( "Client %s has diconnected!" , s . conn . RemoteAddr ( ) . String ( ) )
} else {
log . Print ( err )
s . conn . Close ( )
}
return
}
2022-01-19 21:44:27 +00:00
s . tconn . EndRequest ( id )
2022-01-18 17:26:37 +00:00
log . Printf ( "Received message from %s: %s" , s . conn . RemoteAddr ( ) . String ( ) , message ) // for debugging
2022-01-19 21:44:27 +00:00
err = s . h . Handle ( s , message , id )
2022-01-18 17:26:37 +00:00
if err != nil {
log . Print ( err )
2022-02-05 09:54:41 +00:00
s . tconn . PrintfLine ( protocol . NNTPResponse { Code : 403 , Message : fmt . Sprintf ( "Failed to process command: %s" , err . Error ( ) ) } . String ( ) )
2022-01-18 17:26:37 +00:00
s . conn . Close ( )
return
}
}
}
}
}