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