Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang handlefunc with channel

Tags:

go

I think this question has been asked before (and probably more than once) but I can't find it...

Im learning Go, and I wanted to extend the classical web server example by sending a channel to the "handler".

I have this standard thing:

func hello(w http.ResponseWriter, r *http.Request) {
   io.WriteString(w, "Hello world!")
}

func main() {
    http.HandleFunc("/", hello)
    http.ListenAndServe(":8000", nil)
}

And now I would like the "hello" function to be able to write stuff on a channel, for someone to consume... The way I have done with "normal" functions is to create a channel:

c := make(chan string) 

and pass c in the call to the function. Something like:

dosomething(c)

But... how would I go about doing that if I want "hello" to get access to the channel c?

like image 666
plithner Avatar asked Feb 09 '15 21:02

plithner


2 Answers

There are two other ways to do this (other than exporting your channels as in the previous answer).

The first is to use a function to return another handler function. When the function is returned, it will create a closure around the channel.

func makeHello(logger chan string) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        logger <- r.Host
        io.WriteString(w, "Hello world!")
    }
}

The second is to use a struct which holds the channel as a member and use pointer receiver methods to handle the request...

type DataPasser struct {
    logs chan string
}

func (p *DataPasser) handleHello(w http.ResponseWriter, r *http.Request) {
    p.logs <- r.URL.String()
    io.WriteString(w, "Hello world")
}

This is a full working example (just hit /1 and /2 to see the two examples)

package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    // METHOD 1
    logs := make(chan string)
    go logLogs(logs)
    handleHello := makeHello(logs)

    // METHOD 2
    passer := &DataPasser{logs: make(chan string)}
    go passer.log()

    http.HandleFunc("/1", handleHello)
    http.HandleFunc("/2", passer.handleHello)
    http.ListenAndServe(":9999", nil)
}

// METHOD 1

func makeHello(logger chan string) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        logger <- r.Host
        io.WriteString(w, "Hello world!")
    }
}

func logLogs(logger chan string) {
    for item := range logger {
        fmt.Println("1. Item", item)
    }
}

// METHOD 2

type DataPasser struct {
    logs chan string
}

func (p *DataPasser) handleHello(w http.ResponseWriter, r *http.Request) {
    p.logs <- r.URL.String()
    io.WriteString(w, "Hello world")
}

func (p *DataPasser) log() {
    for item := range p.logs {
        fmt.Println("2. Item", item)
    }
}
like image 169
sberry Avatar answered Sep 27 '22 03:09

sberry


There a few ways to solve this problem, the simplest is to define an exported channel in a package and import said package where ever you want to use the channel.

package mychannel

var Chan = make(chan string)
like image 42
jmaloney Avatar answered Sep 26 '22 03:09

jmaloney