Giter Site home page Giter Site logo

elahe-dastan / hub Goto Github PK

View Code? Open in Web Editor NEW
9.0 2.0 0.0 91 KB

A message delivery system using Go programming language

License: Apache License 2.0

Go 98.12% Dockerfile 1.88%
golang hub message-delivery client-server toy-project example-project tcp

hub's Introduction

Hub

Build Status

Protocol

Server and client can talk to each other using the following set of rules:

Client Server Example
WhoAmI WhoAmI,id client:"WhoAmI"
server:"WhoAmI,1
List List,id1-id2,... client:"List"
server:"List,2-3-4
Send,id-id-...,body Send,body client:"Send,2-3,I will be late
server:"Send,I will be late"

hub's People

Contributors

1995parham avatar elahe-dastan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

hub's Issues

Convert streams to more capable streams

As you saw in Java you can convert streams into streams that have more functionality. One of the best streams in every language is a buffered stream. In Golang we have bufio.Reader and bufio.Writer. You are using them in your project and it is awesome but it would be better if you create them once then use them many times:

rd := bufio.NewReader(conn)

for {
    // use _rd_ as many times as you want
}

bufio.Writer is awesome too and you can use it as follow:

wr := bufio.NewWriter(conn)

for {
    wr.WriteString("Hello World")

    wr.Flush()
}

Please remember that, bufio.Writer is a buffered stream so you must flush it after using it.

https://github.com/elahe-dastan/applifier/blob/9edf273a359ce8dd5fa28281e7fc196c5e1b17d0/internal/server/server.go#L77

Client Error Handling

The server must continue its execution with any cost, but clients must exit with any error to not disturb users with invalid results.

Messages Package

Create the message package that contains the constants for message types.

const (
    WhoAmI = "WhoAmI"
    ListClientIDs = "ListClientIDs"
    ...
)

Besides that, you can define the IncommingMessage into that package.

Interactive client

The way you handle the client is very impressive to me. It reminds me that you can use the libraries like go-prompt to have even more fun client program. I haven't used this library, but I am very interested, so let me know if you start working on this.

Use Koanf instead of Viper

Koanf is another configuration module, and it's way better than the viper.

Koanf has providers and parsers. Providers specify where the configuration is and parsers providers a way for parsing the given configuration. First of all you must define a configuration structure as before:

type(
	// Config holds all configurations
	Config struct {
		Token string   `koanf:"token"`
		Words []string `koanf:"words"`
	}
)

Before anything, we create an instance of Koanf for the current location.

	k := koanf.New(".")

Here you only use the koanf tag to specify the configuration fields name. After that you must load the following locations:

  • Default (specify in an instance of configuration structure)
	// load default configuration from file
	if err := k.Load(structs.Provider(Default(), "konaf"), nil); err != nil {
		logrus.Fatalf("error loading default: %s", err)
	}
  • config.yml
	// load configuration from file
	if err := k.Load(file.Provider("config.yml"), yaml.Parser()); err != nil {
		logrus.Errorf("error loading config.yml: %s", err)
	}
  • Environment Variables
        // Prefix indicates environment variables prefix
	const Prefix = "jasoos_"

	// load environment variables
	if err := k.Load(env.Provider(Prefix, ".", func(s string) string {
		return strings.Replace(strings.ToLower(
			strings.TrimPrefix(s, Prefix)), "_", ".", -1)
	}), nil); err != nil {
		logrus.Errorf("error loading environment variables: %s", err)
	}

Koanf has a provider for structures so you can define Default configuration in an instance of Configuration structure as follow:

// Default return default configuration
// nolint: gomnd
func Default() Config {
	return Config{
		Token: "AwesomeBotToken",
		Words: []string{
			"Hello",
			"Home",
			"Raha",
			"Room",
		},
	}
}

In the end, you unmarshal the configuration from Koanf into an instance of Configuration structure.

	if err := k.Unmarshal("", &instance); err != nil {
		logrus.Fatalf("error unmarshalling config: %s", err)
	}

Control the number of accepted clients

As you may remember in our Java workshop, we have the same problem. When you are using the threads for handling the incoming connections, your system may not be capable of handling the number of threads that you are creating. There are many ways to control the number of threads and block the incoming connections until there is a free slot for them. Check the following ways:

  1. Goroutine pools
  2. Control the acceptance procedure using channel
  3. etc.

https://github.com/elahe-dastan/applifier/blob/9edf273a359ce8dd5fa28281e7fc196c5e1b17d0/internal/server/server.go#L39

Clients Management

You manage clients on the server with the following map:

conn map[net.Conn]string

but I think using the following map is better:

conn map[string]net.Conn

Dockerfile

It would be great to have the Dockerfile for the project since the beginning.

Design a Communication Protocol

Design a protocol for communication between servers and clients. This protocol must contain the message types and their optional payloads.

Make the Maps

Use the make for making the maps as follow:

m := make(map[string]string)

It is more popular than:

m := map[string]string{}

Client Exit

When the client calls, the STOP command program must terminate and exit properly, but it reports the following errors:

2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF
2020/04/02 08:02:15 EOF

And the wired thing here is the state of the server after this command:

Serving 127.0.0.1:48484
2020/04/02 08:02:11 write tcp4 127.0.0.1:8080->127.0.0.1:48484: use of closed network connection
2020/04/02 08:02:11 read tcp4 127.0.0.1:8080->127.0.0.1:48484: use of closed network connection

I think this is a misunderstanding because there must be a command for closing the client without stopping the server.

How to handle Client Configuration

The client is different from the server. Server-side it is normal to have configuration and configuration file but at the client-side users are more comfortable with command-line options:

go run main.go client --server "127.0.0.1:1378"

but at the server-side we have the old way:

cat config.yml
adrr: 0.0.0.0:1378
go run main.go server

Ignore .idea

It would be better if you ignore the the .idea folder in the .gitignore. one way is to use the gitignore.io website and the following commands:

curl -L "http://gitignore.io/api/go,jetbrains+all" > .gitignore

CMD Description

Remove the default description of Cobra from the root command.

Switch-Case is useful

Go has the switch-case statement for providing conditions in your application. You can see its example here.

switch strings.TrimSpace(netData) {
    case message.STOP:
        ....
}

By using switch-case you need to find out how to break the loop from switch-case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.