Forgotten files.
This commit is contained in:
parent
e1b71e5d44
commit
5452ea5b1a
12
.golangci.yaml
Normal file
12
.golangci.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
run:
|
||||
deadline: 5m
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
# Actually not really needed.
|
||||
- gochecknoglobals
|
||||
linters-settings:
|
||||
lll:
|
||||
line-length: 420
|
||||
gocyclo:
|
||||
min-complexity: 40
|
17
commands/exported.go
Normal file
17
commands/exported.go
Normal file
@ -0,0 +1,17 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"log"
|
||||
|
||||
// local
|
||||
"develop.pztrn.name/gonews/gonews/commands/greeting"
|
||||
"develop.pztrn.name/gonews/gonews/commands/quit"
|
||||
)
|
||||
|
||||
func Initialize() {
|
||||
log.Println("Initializing commands...")
|
||||
|
||||
greeting.Initialize()
|
||||
quit.Initialize()
|
||||
}
|
23
commands/greeting/exported.go
Normal file
23
commands/greeting/exported.go
Normal file
@ -0,0 +1,23 @@
|
||||
package greeting
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"log"
|
||||
|
||||
// local
|
||||
"develop.pztrn.name/gonews/gonews/eventer"
|
||||
"develop.pztrn.name/gonews/gonews/networker"
|
||||
)
|
||||
|
||||
func Initialize() {
|
||||
log.Println("Initializing greeting command...")
|
||||
|
||||
eventer.AddEventHandler(&eventer.EventHandler{
|
||||
Command: "internal/greeting",
|
||||
Handler: handler,
|
||||
})
|
||||
}
|
||||
|
||||
func handler(data interface{}) interface{} {
|
||||
return &networker.Reply{Code: "201", Data: "NNTP server is ready, posting prohibited\r\n"}
|
||||
}
|
23
commands/quit/exported.go
Normal file
23
commands/quit/exported.go
Normal file
@ -0,0 +1,23 @@
|
||||
package quit
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"log"
|
||||
|
||||
// local
|
||||
"develop.pztrn.name/gonews/gonews/eventer"
|
||||
"develop.pztrn.name/gonews/gonews/networker"
|
||||
)
|
||||
|
||||
func Initialize() {
|
||||
log.Println("Initializing quit command...")
|
||||
|
||||
eventer.AddEventHandler(&eventer.EventHandler{
|
||||
Command: "commands/quit",
|
||||
Handler: handler,
|
||||
})
|
||||
}
|
||||
|
||||
func handler(data interface{}) interface{} {
|
||||
return &networker.Reply{Code: "205", Data: "NNTP Service exits normally\r\n"}
|
||||
}
|
18
configuration/config.go
Normal file
18
configuration/config.go
Normal file
@ -0,0 +1,18 @@
|
||||
package configuration
|
||||
|
||||
// Represents configuration file structure.
|
||||
type config struct {
|
||||
// Network represents network stack configuration.
|
||||
Network []Network `yaml:"network"`
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
// Address represents address to bing in form of "ip:port".
|
||||
Address string `yaml:"address"`
|
||||
// Limit sets maximum simultaneous connections that can be
|
||||
// processed by worker.
|
||||
Limit int `yaml:"limit"`
|
||||
// Type sets connection type. See networker for available
|
||||
// types.
|
||||
Type string `yaml:"type"`
|
||||
}
|
55
configuration/exported.go
Normal file
55
configuration/exported.go
Normal file
@ -0,0 +1,55 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
// other
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
Cfg *config
|
||||
)
|
||||
|
||||
// Initialize initializes package and parses configuration into struct.
|
||||
func Initialize() {
|
||||
log.Println("Initializing configuration...")
|
||||
|
||||
pathRaw, found := os.LookupEnv("GONEWS_CONFIG")
|
||||
if !found {
|
||||
log.Fatalln("Failed to read configuration - no GONEWS_CONFIG environment variable defined.")
|
||||
}
|
||||
|
||||
// Normalize path.
|
||||
if strings.HasPrefix(pathRaw, "~") {
|
||||
userHomeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to obtain user's home directory path: " + err.Error())
|
||||
}
|
||||
|
||||
pathRaw = strings.Replace(pathRaw, "~", userHomeDir, 1)
|
||||
}
|
||||
absPath, err1 := filepath.Abs(pathRaw)
|
||||
if err1 != nil {
|
||||
log.Fatalln("Failed to get absolute path for configuration file: " + err1.Error())
|
||||
}
|
||||
|
||||
// Read and parse configuration file.
|
||||
fileData, err2 := ioutil.ReadFile(absPath)
|
||||
if err2 != nil {
|
||||
log.Fatalln("Failed to read configuration file data: " + err2.Error())
|
||||
}
|
||||
|
||||
Cfg = &config{}
|
||||
err3 := yaml.Unmarshal(fileData, Cfg)
|
||||
if err3 != nil {
|
||||
log.Fatalln("Failed to parse configuration file: " + err3.Error())
|
||||
}
|
||||
|
||||
log.Printf("Configuration file parsed: %+v\n", Cfg)
|
||||
}
|
94
networker/connection.go
Normal file
94
networker/connection.go
Normal file
@ -0,0 +1,94 @@
|
||||
package networker
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"bufio"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
// local
|
||||
"develop.pztrn.name/gonews/gonews/eventer"
|
||||
)
|
||||
|
||||
// This function is a connection worker.
|
||||
func connectionWorker(conn net.Conn) {
|
||||
remoteAddr := conn.RemoteAddr()
|
||||
log.Printf("accepted connection from %v\n", conn.RemoteAddr())
|
||||
|
||||
defer func() {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
log.Println("Failed to close connection from " + remoteAddr.String() + ": " + err.Error())
|
||||
}
|
||||
log.Println("Connection from " + remoteAddr.String() + " closed")
|
||||
}()
|
||||
|
||||
// Create buffers.
|
||||
r := bufio.NewReader(conn)
|
||||
w := bufio.NewWriter(conn)
|
||||
scanr := bufio.NewScanner(r)
|
||||
|
||||
// Send greeting.
|
||||
greetingData, _ := eventer.LaunchEvent("internal/greeting", nil)
|
||||
greetingReply := greetingData.(*Reply)
|
||||
|
||||
_, err := w.WriteString(greetingReply.Code + " " + greetingReply.Data)
|
||||
if err != nil {
|
||||
log.Println("Failed to write greeting for " + remoteAddr.String() + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
// Start reading for commands.
|
||||
// Every command can be represented as slice where first element
|
||||
// is actual command and all next - parameters.
|
||||
// By default we read only one line per iteration.
|
||||
// ToDo: multiline data parser for posting.
|
||||
for {
|
||||
dataAppeared := scanr.Scan()
|
||||
if !dataAppeared {
|
||||
log.Println("Failed to read data from " + remoteAddr.String() + ": " + scanr.Err().Error())
|
||||
break
|
||||
}
|
||||
|
||||
log.Println("Got data: " + scanr.Text())
|
||||
|
||||
// ToDo: what if we'll upload binary data here?
|
||||
// Not supported yet.
|
||||
data := strings.Split(scanr.Text(), " ")
|
||||
replyRaw, err := eventer.LaunchEvent("commands/"+data[0], data[1:])
|
||||
if err != nil {
|
||||
// We won't break here as this is just logging of appeared error.
|
||||
log.Println("Error appeared while processing command '" + data[0] + "' for " + remoteAddr.String() + ": " + err.Error())
|
||||
}
|
||||
|
||||
// We might have nil in reply, so we'll assume that passed command
|
||||
// is unknown to us.
|
||||
if replyRaw == nil {
|
||||
_, err := w.WriteString(unknownCommandErrorCode + " " + unknownCommandErrorText + "\r\n")
|
||||
if err != nil {
|
||||
log.Println("Failed to write string to socket for " + remoteAddr.String() + ": " + err.Error())
|
||||
break
|
||||
}
|
||||
w.Flush()
|
||||
continue
|
||||
}
|
||||
|
||||
// Every reply will be a reply struct.
|
||||
reply := replyRaw.(*Reply)
|
||||
|
||||
_, err1 := w.WriteString(reply.Code + " " + reply.Data)
|
||||
if err1 != nil {
|
||||
log.Println("Failed to write string to socket for " + remoteAddr.String() + ": " + err1.Error())
|
||||
break
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
// Check for QUIT command.
|
||||
if strings.ToLower(data[0]) == "quit" {
|
||||
log.Println("QUIT command received, closing connection to " + remoteAddr.String())
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
6
networker/errors.go
Normal file
6
networker/errors.go
Normal file
@ -0,0 +1,6 @@
|
||||
package networker
|
||||
|
||||
const (
|
||||
unknownCommandErrorCode = "500"
|
||||
unknownCommandErrorText = "Unknown command"
|
||||
)
|
6
networker/reply.go
Normal file
6
networker/reply.go
Normal file
@ -0,0 +1,6 @@
|
||||
package networker
|
||||
|
||||
type Reply struct {
|
||||
Code string
|
||||
Data string
|
||||
}
|
37
networker/server.go
Normal file
37
networker/server.go
Normal file
@ -0,0 +1,37 @@
|
||||
package networker
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"log"
|
||||
"net"
|
||||
|
||||
// local
|
||||
"develop.pztrn.name/gonews/gonews/configuration"
|
||||
)
|
||||
|
||||
// This function responsible for accepting incoming connections for
|
||||
// each address configuration.
|
||||
func startServer(config configuration.Network) {
|
||||
log.Println("Starting server on " + config.Address + " (type: " + config.Type + ")")
|
||||
|
||||
l, err := net.Listen("tcp", config.Address)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to start TCP server on " + config.Address + ": " + err.Error())
|
||||
}
|
||||
defer func() {
|
||||
err := l.Close()
|
||||
if err != nil {
|
||||
log.Println("Failed to close TCP server on " + config.Address + ": " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
conn, err1 := l.Accept()
|
||||
if err1 != nil {
|
||||
log.Println("Failed to accept new incoming connection: " + err1.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
go connectionWorker(conn)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user