hurlean

package module
v0.0.0-...-d0f61fa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2021 License: MIT Imports: 8 Imported by: 1

README

hurlean

TCP Networking Framework

Installing

$ go get github.com/danielblagy/hurlean

Import

import(
	"github.com/danielblagy/hurlean"
	//...
)

Console Chat Example

Chat Server Application
Chat Client Application

How To Use

Let's create a simple server and client apps. The client app will be able to query the server for current time.

Example Server App

Let's start by creating the server program

First we import packages that we'll need

package main

import (
	"github.com/danielblagy/hurlean"
	"fmt"
	"time"
	"bufio"
	"os"
)

Then we implement hurlean.ServerFunctionalityProvider interface.
With this interface we define the behavior of our server application.\

First we define the struct of our interface implementation. Here we can put our client application state.
In this simple example we won't need much, only a *bufio.Scanner variable to store the initialized console scanner. We the scanner we can get console input from the user of our server application. We'll provide two commands: 'exit', which will stop the server, and 'disconnect' which will force-disconnect all the currently connected users.

type ExampleClientHandler struct{}

type ExampleServerFunctionalityProvider struct{
	// here we can store application-specific data
	scanner *bufio.Scanner
}

Next we implement functions that define the behavior of our server in the case of any client activity.

// executed once for each client
func (fp ExampleServerFunctionalityProvider) OnClientConnect(si *hurlean.ServerInstance, id uint32) {
	
	fmt.Printf("Client %v has connected to the server\n", id)
}

// executed once for each client
func (fp ExampleServerFunctionalityProvider) OnClientDisconnect(si *hurlean.ServerInstance, id uint32) {
	
	fmt.Printf("Client %v has disconnected from the server\n", id)
}

// executed each time the server gets a message from a client
func (fp ExampleServerFunctionalityProvider) OnClientMessage(si *hurlean.ServerInstance, id uint32, message hurlean.Message) {
	
	fmt.Printf("Message from %v: %v\n", id, message)
	
	if message.Type == "get current time" {
		currentTimeMessage := hurlean.Message{
			Type: "time",
			Body: time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006"),	// current time
		}
		si.Send(id, currentTimeMessage)
		
		fmt.Printf("Current time has been sent to %v\n", id)
	} else {
		fmt.Printf("Unknown message type '%v'\n", message.Type)
	}
}

Now let's implement the functions that define the logic of our server program.

// executed once when the server instance is initialized
func (fp ExampleServerFunctionalityProvider) OnServerInit(serverInstance *hurlean.ServerInstance) {
	// empty for this simple example
}

// executed continuously in a loop when the server is running
func (fp ExampleServerFunctionalityProvider) OnServerUpdate(serverInstance *hurlean.ServerInstance) {
	
	// get console input from the server administrator (the app user)
	if fp.scanner.Scan() {
		switch (fp.scanner.Text()) {
		case "exit":
			serverInstance.Stop()
			
		case "disconnect":
			serverInstance.DisconnectAll()
		}
	}
}

Now, to the main function. Here we start the server on port 4545 and provide interfaces implementations and the state.
In the case of failure to start the server, error will be returned.

func main() {
	
	// init server state
	exampleServerFunctionalityProvider := ExampleServerFunctionalityProvider{
		scanner: bufio.NewScanner(os.Stdin),
	}
	
	if err := hurlean.StartServer("4545", exampleServerFunctionalityProvider); err != nil {
		fmt.Println(err)
	}
}

Full source

Example Client App

Import packages first

package main

import (
	"github.com/danielblagy/hurlean"
	"fmt"
	"bufio"
	"os"
)

Then we need to implement hurlean.ClientFunctionalityProvider interface.
Much like with server state, we're going to define client state as well.

type ExampleClientFunctionalityProvider struct{
	// here we can store application-specific data
	scanner *bufio.Scanner
}

We proceed by implementing the interface functions.
Here we define how we should respond to the messages coming from the server.

// executed each time the client gets a message from the server
func (fp ExampleClientFunctionalityProvider) OnServerMessage(clientInstance *hurlean.ClientInstance, message hurlean.Message) {
	
	if message.Type == "time" {
		fmt.Printf("Current time: %v\n\n", message.Body)
	} else {
		fmt.Printf("Unknown message type '%v'", message.Type)
	}
}

Now we need to implement functions that define the client application behavior.

// executed once when the client instance is initialized
func (fp ExampleClientFunctionalityProvider) OnClientInit(clientInstance *hurlean.ClientInstance) {
	// empty for this simple example
}

// executed continuously in a loop when the client is running
func (fp ExampleClientFunctionalityProvider) OnClientUpdate(clientInstance *hurlean.ClientInstance) {
	
	// get console input from the user
	if fp.scanner.Scan() {
		switch (fp.scanner.Text()) {
		case "time":
			getTimeMessage := hurlean.Message{
				Type: "get current time",
				Body: "",
			}
			clientInstance.Send(getTimeMessage)
			
		case "disconnect":
			clientInstance.Disconnect()
		}
	}
}

And finally, the main function where we start the client application.
In the case of failure to connect to the server, error will be returned.

func main() {
	
	// init client state
	exampleClientFunctionalityProvider := ExampleClientFunctionalityProvider{
		scanner: bufio.NewScanner(os.Stdin),
	}
	
	if err := hurlean.ConnectToServer(
		"localhost", "4545", exampleClientFunctionalityProvider); err != nil {
		fmt.Println(err)
	}
}

Full source

Example Server App Full Source
package main


import (
	"github.com/danielblagy/hurlean"
	"fmt"
	"time"
	"bufio"
	"os"
)


type ExampleServerFunctionalityProvider struct{
	// here we can store application-specific data
	scanner *bufio.Scanner
}

// executed once for each client
func (fp ExampleServerFunctionalityProvider) OnClientConnect(si *hurlean.ServerInstance, id uint32) {
	
	fmt.Printf("Client %v has connected to the server\n", id)
}

// executed once for each client
func (fp ExampleServerFunctionalityProvider) OnClientDisconnect(si *hurlean.ServerInstance, id uint32) {
	
	fmt.Printf("Client %v has disconnected from the server\n", id)
}

// executed each time the server gets a message from a client
func (fp ExampleServerFunctionalityProvider) OnClientMessage(si *hurlean.ServerInstance, id uint32, message hurlean.Message) {
	
	fmt.Printf("Message from %v: %v\n", id, message)
	
	if message.Type == "get current time" {
		currentTimeMessage := hurlean.Message{
			Type: "time",
			Body: time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006"),	// current time
		}
		si.Send(id, currentTimeMessage)
		
		fmt.Printf("Current time has been sent to %v\n", id)
	} else {
		fmt.Printf("Unknown message type '%v'\n", message.Type)
	}
}

// executed once when the server instance is initialized
func (fp ExampleServerFunctionalityProvider) OnServerInit(serverInstance *hurlean.ServerInstance) {
	// empty for this simple example
}

// executed continuously in a loop when the server is running
func (fp ExampleServerFunctionalityProvider) OnServerUpdate(serverInstance *hurlean.ServerInstance) {
	
	// get console input from the server administrator (the app user)
	if fp.scanner.Scan() {
		switch (fp.scanner.Text()) {
		case "exit":
			serverInstance.Stop()
			
		case "disconnect":
			serverInstance.DisconnectAll()
		}
	}
}


func main() {
	
	// init server state
	exampleServerFunctionalityProvider := ExampleServerFunctionalityProvider{
		scanner: bufio.NewScanner(os.Stdin),
	}
	
	if err := hurlean.StartServer("4545", exampleServerFunctionalityProvider); err != nil {
		fmt.Println(err)
	}
}
Example Client App Full Source
package main


import (
	"github.com/danielblagy/hurlean"
	"fmt"
	"bufio"
	"os"
)


type ExampleClientFunctionalityProvider struct{
	// here we can store application-specific data
	scanner *bufio.Scanner
}

// executed each time the client gets a message from the server
func (fp ExampleClientFunctionalityProvider) OnServerMessage(clientInstance *hurlean.ClientInstance, message hurlean.Message) {
	
	if message.Type == "time" {
		fmt.Printf("Current time: %v\n\n", message.Body)
	} else {
		fmt.Printf("Unknown message type '%v'", message.Type)
	}
}

// executed once when the client instance is initialized
func (fp ExampleClientFunctionalityProvider) OnClientInit(clientInstance *hurlean.ClientInstance) {
	// empty for this simple example
}

// executed continuously in a loop when the client is running
func (fp ExampleClientFunctionalityProvider) OnClientUpdate(clientInstance *hurlean.ClientInstance) {
	
	// get console input from the user
	if fp.scanner.Scan() {
		switch (fp.scanner.Text()) {
		case "time":
			getTimeMessage := hurlean.Message{
				Type: "get current time",
				Body: "",
			}
			clientInstance.Send(getTimeMessage)
			
		case "disconnect":
			clientInstance.Disconnect()
		}
	}
}


func main() {
	
	// init client state
	exampleClientFunctionalityProvider := ExampleClientFunctionalityProvider{
		scanner: bufio.NewScanner(os.Stdin),
	}
	
	if err := hurlean.ConnectToServer(
		"localhost", "4545", exampleClientFunctionalityProvider); err != nil {
		fmt.Println(err)
	}
}

For more complex example check out the console chat example

Documentation

Index

Constants

This section is empty.

Variables

View Source
var EnableDebug bool = true

controls the debug prints

Functions

func ConnectToServer

func ConnectToServer(ip string, port string, clientFunctionalityProvider ClientFunctionalityProvider) error

Attempts to connect to the server on ip:port returns error on failure

func StartServer

func StartServer(port string, serverFunctionalityProvider ServerFunctionalityProvider) error

Starts a server on port returns error on failure serverState parameter can be of any type and will be accessible via *hurlean.ServerInstance

Types

type ClientFunctionalityProvider

type ClientFunctionalityProvider interface {

	// Is called when the client receives a message from the server,
	// 'message' is the received message
	OnServerMessage(clientInstance *ClientInstance, message Message)

	// Is called once, when the client application starts
	OnClientInit(clientInstance *ClientInstance)

	// Is called on each client update, used as a 'main' logic function,
	// e.g. getting an input from the user of the client application
	OnClientUpdate(clientInstance *ClientInstance)
}

type ClientInstance

type ClientInstance struct {
	Connected bool
	Conn      net.Conn
}

When the server connects to the server with hurlean.ConnectToServer function call, ClientInstance object will be created on success. Client Instance is used to control the client's state and send messages to the server

func (*ClientInstance) Disconnect

func (ci *ClientInstance) Disconnect()

Disconnects from the server

func (ClientInstance) Send

func (ci ClientInstance) Send(message Message)

Sends a message to the server

type Message

type Message struct {
	Type string
	Body string
}

hurlean.Message objects is data that can be sent and received via network

type ServerFunctionalityProvider

type ServerFunctionalityProvider interface {

	// Is called when a new client connect to the server,
	// 'id' is the new clients's id
	OnClientConnect(si *ServerInstance, id uint32)

	// Is called when a client disconnects from the server,
	// 'id' is the disconnected clients's id
	OnClientDisconnect(si *ServerInstance, id uint32)

	// Is called when the server receives a message from a client,
	// 'id' is the clients's id
	// 'message' is the received message
	OnClientMessage(si *ServerInstance, id uint32, message Message)

	// Is called once, when the server application starts,
	OnServerInit(serverInstance *ServerInstance)

	// Is called on each server update, used as a 'main' logic function,
	// e.g. getting an input from the user of the server application
	OnServerUpdate(serverInstance *ServerInstance)
}

type ServerInstance

type ServerInstance struct {
	IDCounter uint32
	Running   bool
	Clients   map[uint32]net.Conn

	State interface{}
	// contains filtered or unexported fields
}

When the server is started with hurlean.StartServer function call, ServerInstance object will be created on success. Server Instance is used to control the server's state and send messages to clients

func (*ServerInstance) Disconnect

func (si *ServerInstance) Disconnect(id uint32)

Disconnects the client from the server

func (*ServerInstance) DisconnectAll

func (si *ServerInstance) DisconnectAll()

Disconnects all clients from the server

func (ServerInstance) Send

func (si ServerInstance) Send(id uint32, message Message)

Sends a message to the client with id

func (ServerInstance) SendAll

func (si ServerInstance) SendAll(message Message)

Sends a message to all the clients

func (*ServerInstance) Stop

func (si *ServerInstance) Stop()

Stops the server

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL