$ go get github.com/danielblagy/hurlean
import(
"github.com/danielblagy/hurlean"
//...
)
Chat Server Application
Chat Client Application
Let's create a simple server and client apps. The client app will be able to query the server for current time.
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)
}
}
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)
}
}
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)
}
}
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