How to do it...

These steps cover writing and running your application:

  1. From your Terminal or console application, create a new directory called ~/projects/go-programming-cookbook/chapter10/pipeline and navigate to it.
  2. Run the following command:
$ go mod init github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pipeline

You should see a file called go.mod that contains the following content:

module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pipeline    
  1. Copy the tests from ~/projects/go-programming-cookbook-original/chapter10/pipeline, or use this as an opportunity to write some of your own code!
  2. Create a file called worker.go with the following content:
        package pipeline

import "context"

// Worker have one role
// that is determined when
// Work is called
type Worker struct {
in chan string
out chan string
}

// Job is a job a worker can do
type Job string

const (
// Print echo's all input to
// stdout
Print Job = "print"
// Encode base64 encodes input
Encode Job = "encode"
)

// Work is how to dispatch a worker, they are assigned
// a job here
func (w *Worker) Work(ctx context.Context, j Job) {
switch j {
case Print:
w.Print(ctx)
case Encode:
w.Encode(ctx)
default:
return
}
}
  1. Create a file called print.go with the following content:
        package pipeline

import (
"context"
"fmt"
)

// Print prints w.in and repalys it
// on w.out
func (w *Worker) Print(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case val := <-w.in:
fmt.Println(val)
w.out <- val
}
}
}
  1. Create a file called encode.go with the following content:
        package pipeline

import (
"context"
"encoding/base64"
"fmt"
)

// Encode takes plain text as int
// and returns "string => <base64 string encoding>
// as out
func (w *Worker) Encode(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case val := <-w.in:
w.out <- fmt.Sprintf("%s => %s", val,
base64.StdEncoding.EncodeToString([]byte(val)))
}
}
}
  1. Create a file called pipeline.go with the following content:
        package pipeline

import "context"

// NewPipeline initializes the workers and
// connects them, it returns the input of the pipeline
// and the final output
func NewPipeline(ctx context.Context, numEncoders, numPrinters
int) (chan string, chan string) {
inEncode := make(chan string, numEncoders)
inPrint := make(chan string, numPrinters)
outPrint := make(chan string, numPrinters)
for i := 0; i < numEncoders; i++ {
w := Worker{
in: inEncode,
out: inPrint,
}
go w.Work(ctx, Encode)
}

for i := 0; i < numPrinters; i++ {
w := Worker{
in: inPrint,
out: outPrint,
}
go w.Work(ctx, Print)
}
return inEncode, outPrint
}
  1. Create a new directory named example and navigate to it.
  2. Create a file named main.go with the following content:
        package main

import (
"context"
"fmt"

"github.com/PacktPublishing/
Go-Programming-Cookbook-Second-Edition/
chapter10/pipeline"
)

func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()

in, out := pipeline.NewPipeline(ctx, 10, 2)

go func() {
for i := 0; i < 20; i++ {
in <- fmt.Sprint("Message", i)
}
}()

for i := 0; i < 20; i++ {
<-out
}
}
  1. Run go run main.go.
  2. You may also run the following commands:
$ go build
$ ./example

You should now see the following output:

$ go run main.go
Message3 => TWVzc2FnZTM=
Message7 => TWVzc2FnZTc=
Message8 => TWVzc2FnZTg=
Message9 => TWVzc2FnZTk=
Message5 => TWVzc2FnZTU=
Message11 => TWVzc2FnZTEx
Message10 => TWVzc2FnZTEw
Message4 => TWVzc2FnZTQ=
Message12 => TWVzc2FnZTEy
Message6 => TWVzc2FnZTY=
Message14 => TWVzc2FnZTE0
Message13 => TWVzc2FnZTEz
Message0 => TWVzc2FnZTA=
Message15 => TWVzc2FnZTE1
Message1 => TWVzc2FnZTE=
Message17 => TWVzc2FnZTE3
Message16 => TWVzc2FnZTE2
Message19 => TWVzc2FnZTE5
Message18 => TWVzc2FnZTE4
Message2 => TWVzc2FnZTI=
  1. The go.mod file may be updated and the go.sum file should now be present in the top-level recipe directory.
  2. If you copied or wrote your own tests, go up one directory and run go test. Ensure that all the tests pass.