Receive from non-chan type *bool - pointers

I want to daemonize myapp but I have one big problem. The channels I'm using are of type chan struct{}.
However, with the package getopt (flag package), my flags are of type *bool, so I don't know how can I modify myapp.
It's not enough with channels type bool. I'm sure there are a concept that I don't understand. I attach you the code:
package main
import (
"os"
"syscall"
"time"
"github.com/pborman/getopt/v2"
"github.com/sevlyar/go-daemon"
)
var (
done = make(chan struct{})
optQuit = make(chan struct{})
optRun = make(chan struct{})
)
func TermHandler(sig os.Signal) error {
optQuit <- struct{}{}
if sig == syscall.SIGQUIT {
<-done
}
return nil
}
func main() {
optHelp := getopt.BoolLong("help", 'h', "Help")
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")
if *optHelp {
getopt.Usage()
os.Exit(0)
}
// Create pid file
cntxt := &daemon.Context{
PidFileName: "/var/run/myapp.pid",
PidFilePerm: 0644,
WorkDir: "./",
Umask: 027,
Args: []string{"[Z]"},
}
if len(daemon.ActiveFlags()) > 0 {
d, _ := cntxt.Search()
daemon.SendCommands(d)
return
}
d, err := cntxt.Reborn()
if d != nil {
return
}
if err != nil {
os.Exit(1)
}
defer cntxt.Release()
// Define ticker
ticker := time.NewTicker(time.Second)
myapp := true
// Loop
for myapp {
select {
// Case sleep
case <- ticker.C:
time.Sleep(time.Second)
// Case QUIT
case <- optQuit:
done <- struct{}{}
myapp = false
ticker.Stop()
os.Exit(0)
// Case RUN
case <- optRun:
// Executes a goroutine...
}
}
}
With go install, I can see this errors:
./main.go:72: invalid operation: <-optQuit (receive from non-chan type *bool)
./main.go:79: invalid operation: <-optRun (receive from non-chan type *bool)
I don't know how I should modify the channels (done, optQuit of type struct{}), to resolve this...
P.S.: I show you an example that I did. It runs as daemon and each minute, it executes the function Writer().
After, if you type zdaemon -z quit, the app does a graceful shutdown. You can run it in your machines:
https://play.golang.org/p/RVq7M7usEj

Those two lines in your main function shadow your global variable declaration:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")
If you only use them, to get a nice usage, why not create a usage function
yourself?
If you insist on using getopt just to create a usage, do
_ = getopt.BoolLong("quit", 0, "Help")
_ = getopt.BoolLong("run", 'r', "Help")
instead.
You also need to call getopt.Parse() before using *optHelp.
The resulting message
Usage: test [-hr] [--quit] [parameters ...]
-h, --help Help
--quit Help
-r, --run Help
seems to be less than helpful. Why not just do
fmt.Printf(`
Usage: test
This program will start a daemon service, which you can use like this ...
`)

You define optQuit = make(chan struct{}) globally and then shadow it in main: optQuit := getopt.BoolLong("quit", 0, "Help").
So in main optQuit is a bool, not a chan
Remove those two lines in main:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")

Related

Downloading with POST function a file with golang gingonic

this is my function:
func downloadDoc(c *gin.Context) {
var fileToSearch service.ApDocumentsMedia
if err := c.BindJSON(&fileToSearch); err != nil {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, "is not binding!")
return
}
var file service.ApDocumentsMedia
if err := db.Where("uuid = ?", fileToSearch.Uuid).First(&file); err.RowsAffected <= 0 {
c.IndentedJSON(http.StatusNotFound, "Document not founded!")
return
}
c.Header("Content-Description", "File Transfer")
c.Header("Content-Transfer-Encoding", "binary")
c.Header("Content-Disposition", "attachment; filename="+strconv.Quote(file.Path))
c.Header("Content-Type", "application/octet-stream; charset=utf-8")
c.File(file.Path)
c.IndentedJSON(http.StatusOK, "File inviato")
}
but then when I go to call the function (using the frontend) it gives me this error:
http: panic serving 127.0.0.1:50138: http: wrote more than the declared Content-Length
goroutine 24 [running]:
net/http.(*conn).serve.func1()
/home/stage01/sdk/go1.18.3/src/net/http/server.go:1825 +0xbf
panic({0xac00e0, 0xc000020ab0})
/home/stage01/sdk/go1.18.3/src/runtime/panic.go:844 +0x258
github.com/gin-gonic/gin.(*Context).Render(0xc0000b2900, 0xc8, {0xc8d318, 0xc000245950})
/home/stage01/go/pkg/mod/github.com/gin-gonic/gin#v1.8.1/context.go:911 +0x112
github.com/gin-gonic/gin.(*Context).IndentedJSON(...)
/home/stage01/go/pkg/mod/github.com/gin-gonic/gin#v1.8.1/context.go:928
main.downloadDoc(0xc0000b2900)
/home/stage01/Scrivania/minia_git/docmanagement-alexperrucci/api/main.go:74 +0x36d
github.com/gin-gonic/gin.(*Context).Next(...)
/home/stage01/go/pkg/mod/github.com/gin-gonic/gin#v1.8.1/context.go:173
github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc000449520, 0xc0000b2900)
/home/stage01/go/pkg/mod/github.com/gin-gonic/gin#v1.8.1/gin.go:616 +0x671
github.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc000449520, {0xc8f430?, 0xc0004ee620}, 0xc0000b2700)
/home/stage01/go/pkg/mod/github.com/gin-gonic/gin#v1.8.1/gin.go:572 +0x1dd
net/http.serverHandler.ServeHTTP({0xc8c968?}, {0xc8f430, 0xc0004ee620}, 0xc0000b2700)
/home/stage01/sdk/go1.18.3/src/net/http/server.go:2916 +0x43b
net/http.(*conn).serve(0xc00054b360, {0xc8ff38, 0xc00028f290})
/home/stage01/sdk/go1.18.3/src/net/http/server.go:1966 +0x5d7
created by net/http.(*Server).Serve
/home/stage01/sdk/go1.18.3/src/net/http/server.go:3071 +0x4db
This problem is given to me when once I click on the button that makes the post call (with the uuid of the file) it gives me this error and I don't understand why, would anyone know how to help me?

Why does printing the error from net.Interfaces crash my program?

I'm trying to get a list of system interfaces on my machine, I'm using the net package, which is defined here.
I have this tiny little snippet of code, which crashes when trying to print out the error, and I can't figure out why the error is sigsev'ing on me. It's supposed to return an error, or nil right?
I've ran this code with sudo, root and under a regular user account thinking it might be a permissions thing for the network interface, but it persists amongst all user levels.
package main
import (
"net"
"fmt"
)
func main() {
var err error
var interfaces []net.Interface
var ifString []string
interfaces, err = net.Interfaces()
fmt.Printf("%v",interfaces)
if err != nil {
for _, v := range interfaces {
ifString = append(ifString, v.Name)
}
} else {
fmt.Printf(err.Error())
ifString = append(ifString, "unable to get system interfaces")
}
}
Program output is as follows when running go build and executing it:
[{1 65536 lo up|loopback} {2 1500 eno1 b8:cc:3c:8e:d4:d3 up|broadcast|multicast} {9 1500 tun0 up|pointtopoint|multicast}]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x4a5269]
goroutine 1 [running]:
main.main()
/home/andrew/interface/borked.go:20 +0x269
You are receiving a nil pointer dereference because that's exactly what you're doing.
Given the following if statement in your code:
if err != nil {
for _, v := range interfaces {
ifString = append(ifString, v.Name)
}
} else {
fmt.Printf(err.Error())
...
}
The else is reached when err is nil. Yet you are attempting to access a field in it: err.Error(), dereferencing a nil pointer.
You need to invert your if statement, it's the wrong way around.

Implementing Long live tcp connection using ninenine ranch

I'm trying to implement a long live TCP connection with ninnenine ranch
erlang library .
But looking at the documentation i cannot see a way of doing that.
Also i have written my own ranch protocol as shown below
start_link(Ref, _Socket, Transport, Opts) ->
Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]),
{ok, Pid}.
init(Ref, Transport, _Opts = []) ->
{ok, Socket} = ranch:handshake(Ref),
loop(Socket, Transport).
loop(Socket, Transport) ->
case Transport:recv(Socket, 0, 5000) of
{ok, Data} when Data =/= <<4>> ->
%% Transport:send(Socket, Data),
io:format("~w Connction accpted~n", [Data]);
_ -> ok
%%, Transport:close(Socket)
end.
as you can see i have commented the Transport:close(Socket) and i'm not sending any response to the client since Transsport:send(socket,Data) is also commented thinking that is was going to solve the problem but still, my connections where closing immediately as opened . i have a golang client shown below
package main
import (
"fmt"
"log"
"net"
)
func main(){
conn, err := net.Dial("tcp", "localhost:5555")
if err != nil {
fmt.Println(err)
}
fmt.Println(conn /*, i*/)
conn.Write(XMLData)
buffer := make([]byte, 10024)
n, err := conn.Read(buffer)
fmt.Println(buffer[:n])
//conn.Close()
}
i though it was a time out in ranch causing that. I searched and i found that in the ranch, in the the file src/ranch_tcp.erl , we have the function listen implemented as below
listen(Opts) ->
Opts2 = ranch:set_option_default(Opts, backlog, 1024),
Opts3 = ranch:set_option_default(Opts2, nodelay, true),
Opts4 = ranch:set_option_default(Opts3, send_timeout, 30000),
Opts5 = ranch:set_option_default(Opts4, send_timeout_close, true),
%% We set the port to 0 because it is given in the Opts directly.
%% The port in the options takes precedence over the one in the
%% first argument.
gen_tcp:listen(0, ranch:filter_options(Opts5, disallowed_listen_options(),
[binary, {active, false}, {packet, raw}, {reuseaddr, true}])).
As you can see there is a timeout option specifically Opts5 Opts5 = ranch:set_option_default(Opts4, send_timeout_close, true) and Opts4 Opts4 = ranch:set_option_default(Opts3, send_timeout, 30000),.I disabled them but still not working . So what am i supposed to do to have a long live tcp connection using ranch.
Your protocol implementation has a flaw
loop(Socket, Transport) ->
case Transport:recv(Socket, 0, 5000) of
{ok, Data} when Data =/= <<4>> ->
%% Transport:send(Socket, Data),
io:format("~w Connction accpted~n", [Data]);
_ -> ok
%%, Transport:close(Socket)
end.
You do not call the loop/2 recursively in any of your case clause branch, thus the your protocol process dies when loop/2 returns bringing tcp connection down.

Go stdout stream from async command

I want to use GO to run an asynchronous command on windows 10. The command I am running is blocking, and if run directly from the terminal it provides a constant steam of status messages until ctrl-c
I want to run that command from GO via exec and catch the output from the exec command to the terminal in real time, i.e. not only when the GO application terminates.
I have tried numerous examples but with not success, I just get a blank terminal and even after exiting the GO application, I don't see the output from the command I executed.
You can use cmd.StdoutPipe to do that:
cmd := exec.Command(cmdName, cmdArgs...)
cmdReader, _ := cmd.StdoutPipe()
scanner := bufio.NewScanner(cmdReader)
done := make(chan bool)
go func() {
for scanner.Scan() {
fmt.Printf(scanner.Text())
}
done <- true
}()
cmd.Start()
<- done
err = cmd.Wait()
You can use io.MultiWriter to capture output and forward it to stdout and stderr.
var stdoutBuf, stderrBuf bytes.Buffer
cmd := exec.Command("/some-command")
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
err := cmd.Start() // Starts command asynchronously
if err != nil {
fmt.Printf(err.Error())
}

http.Server Serve method hangs when calling Shutdown immediately

I have an issue with Go's http.Server, which I'm embedding in a struct that is supposed to control the server startup and shutdown. The struct looks like this:
type HTTPListen struct {
Consumers []pipeline.Consumer
Cfg HTTPListenConfig
Srv *http.Server
Logger log.Logger
wg *sync.WaitGroup
mu sync.Mutex
state State
}
The issue is that in my test code, I call my struct's Start() method (which in turn runs the Serve() method on the http.Server), check a few vars, and then call Stop(), whitch Shutdown()s the server and then waits for the http.Server to exit (return err from the Serve() method).
Now, for some reason, the Serve() method seems to just hang on the WaitGroup.Wait(), when I try to shutdown the server immediately after starting. When I add a short pause (tried 100ms), or when running the tests with the race detector, It works just fine.
Not sure if it matters, but there are no incoming requests between calling Serve() and Shutdown().
EDIT: link to a playground minimal example. If you comment out the time.Sleep call, the program hangs.
Here is the relevant code for the two methods:
func (h *HTTPListen) Start() error {
h.Logger.Log("msg", "starting HTTPListen input")
addr := h.Cfg.ListenAddr
ln, err := net.Listen("tcp", addr)
if err != nil {
h.Logger.Log("msg", "failed to create listener on tcp/"+addr+": "+err.Error())
h.setState(StateFailed)
return err
}
h.wg.Add(1)
go func() {
defer h.wg.Done()
err := h.Srv.Serve(ln)
h.Logger.Log("msg", "HTTP server stopped: "+err.Error())
}()
h.setState(StateStarted)
h.Logger.Log("msg", "HTTPListen input started")
return nil
}
Stop method:
func (h *HTTPListen) Stop() error {
h.Logger.Log("msg", "stopping HTTPListen input")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
if err := h.Srv.Shutdown(ctx); err != nil {
h.Logger.Log("msg", "HTTP server shutdown deadline expired")
}
h.wg.Wait()
h.setState(StateStopped)
h.Logger.Log("msg", "HTTPListen input stopped")
return nil
}
Log output:
kwz#cyclone ~/s/stblogd> go test -v ./pkg/pipeline/input/ -run TestHTTPListen_StartStop
=== RUN TestHTTPListen_StartStop
msg="starting HTTPListen input"
msg="HTTPListen input started"
msg="stopping HTTPListen input"
... hangs indefinitely
Log output when running tests with the race detector:
kwz#cyclone ~/s/stblogd> go test -race -v ./pkg/pipeline/input/ -run TestHTTPListen_StartStop
=== RUN TestHTTPListen_StartStop
msg="starting HTTPListen input"
msg="HTTPListen input started"
msg="stopping HTTPListen input"
msg="HTTP server stopped: http: Server closed"
msg="HTTPListen input stopped"
--- PASS: TestHTTPListen_StartStop (0.00s)
PASS
ok stblogd/pkg/pipeline/input 1.007s
I'm tempted to just slap a short delay on the test and call it a day, but I would like to know why it behaves like this.
This is a known issue, see this thread:
https://github.com/golang/go/issues/20239
Hopefully they will fix it soon but for now it sounds like adding a short delay in your test is the simplest solution - it probably doesn't come up in real world use much because you won't trigger a shutdown so soon after starting.

Resources