Forgotten files.
This commit is contained in:
		
							
								
								
									
										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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user