I have an HTTP server that returns the "uptime" value. The short version of the code:
package main
import (
"fmt"
"net/http"
"time"
)
var startup time.Time
func main() {
startup = time.Now()
http.HandleFunc("/", RootHandler)
http.ListenAndServe(":39000", nil)
}
func RootHandler(w http.ResponseWriter, r *http.Request) {
now := time.Now()
fmt.Fprintf(w, "startup: %s\nnow: %s\nuptime (.Since): %s\nuptime (.Sub): %s",
startup.Format("2006-01-02 15:04:05"),
now.Format("2006-01-02 15:04:05"),
time.Since(startup).Round(time.Second),
now.Sub(startup).Round(time.Second),
)
}
I started the server at 22:10:33 and after about 1h10m I put my computer to sleep. In the morning, after the computer awake, I got the next response:
startup: 2021-11-18 22:10:33
now: 2021-11-19 05:35:20
uptime (.Since): 1h13m14s
uptime (.Sub): 1h13m14s
I'm working on windows, but the code was executed from WSL v2. Can someone explain why is time calculated wrong?
P.S. If I'm running directly from windows - the response is fine (time difference calculated correctly).
Your code seems fine. From my understanding WSL v2 is it's own environment. In which case, it's getting the time from there. I would check the time on the system.
https://tomssl.com/fixing-clock-drift-in-wsl2-using-windows-terminal/
Related
This question already has answers here:
Go Auto-Recompile and Reload Server on file change
(12 answers)
Closed 2 years ago.
Created basic web app and it is running on localhost:8080, I have to restart the server on each file change.
File changes take affect Ctrl +c (terminate program)and run again go program go run hello.go.
We do not want to terminate program of each file changes. If we do any changes and refresh browser new change take affect like PHP language
EX
First Program
package main
import (
"fmt"
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8080", nil)
}
Second Program
package main
import (
"fmt"
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Happy Coding")
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8080", nil)
}
Anyone have a solution to this?
You have to understand that Go & PHP are not the same at all. Go is a statically-typed, COMPILED language -- where PHP is a dynamically-typed, INTERPRETED language.
So using some special third party solution like the one mentioned in the comment above by #AyushGupta is probably your best bet. What you described in your question is the workflow when building services with Go. You compile a binary, run it & repeat when you make changes.
The code below comes from Todd Mcleod's Golang web-dev course. What I fail to understand - even watching his video's over and over and googling everything about methods- is the following: The method ServeHTTP is attached to type hotdog, but is never ran. Still the code inside the method (in this case Fprintln(...) is executed. (When you run this code and go to localhost:8080, it diesplays "Any code you want in this func".) Could anyone explain me why this is?
Thanks a lot!
package main
import (
"fmt"
"net/http"
)
type hotdog int
func (m hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Any code you want in this func")
}
func main() {
var d hotdog
http.ListenAndServe(":8080", d)
}
It is run. ListenAndServe calls it for every request made to your server.
this function is run when the type hotdog is used
func (m hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Any code you want in this func")
}
in the main you create variable d with the type hotdog,
then in the ListenAndServe and you tell your code to use variable d every time someone connects to your server and because d is of type hotdog your first function is run everytime someone connects
func main() {
var d hotdog
http.ListenAndServe(":8080", d)
}
Since you passed hotdog, which implements ServeHTTP, as a handler, every request received will be sent to hotdog's ServeHTTP.
I have a tests which looks like:
package tst
import (
"testing"
"github.com/demas/cowl-go/pkg/postgres"
"log"
"os"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/demas/cowl-go/pkg/quzx-crawler"
"github.com/SlyMarbo/rss"
"time"
_ "github.com/lib/pq"
)
func TestMain(m *testing.M) {
prepare()
retCode := m.Run()
os.Exit(retCode)
}
func prepare() {
connectionString := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
os.Getenv("DBUSER"),
os.Getenv("DBPASS"),
os.Getenv("DBHOST"),
os.Getenv("DBPORT"),
os.Getenv("DBNAME"))
db, err := sqlx.Open("postgres", connectionString)
if err != nil {
log.Fatal(err)
}
db.Exec(`DELETE FROM Settings`)
db.Exec(`DELETE FROM HackerNews`)
// ....
}
Tests works fine if I keep in the root project folder, but if I move them to tst folder I get error message:
D:\development\gopath\src\github.com\demas\cowl-go\tst>go test -v
2017/03/31 16:30:06 sql: unknown driver "postgres" (forgotten import?)
exit status 1
FAIL github.com/demas/cowl-go/tst 0.085s
Why ?
As already mentioned by #JimB in the comments, the error means that you're trying to open a db connection, using sqlx.Open, without first importing a db driver. This can be fixed by, in your case, adding this _ "github.com/lib/pq" import spec.
If, even after adding that import, you're still seeing the same error, then that means that one of your dependencies is also trying to open a db connection without first importing the necessary driver.
Please note that while log.Fatal is a nice and clean way to stop your program it can sometimes be lacking, as you already know. You might want to consider using panic instead, its output is much more chaotic but, on the other hand, you'll get the line number and file name that caused the panic and eventually you'll learn to parse it quickly.
I am testing http custom endpoint for beego
package test
import (
"github.com/astaxie/beego"
. "github.com/smartystreets/goconvey/convey"
_ "golife-api-cons/routers"
"net/http"
"net/http/httptest"
"path/filepath"
"runtime"
"testing"
)
func init() {
_, file, _, _ := runtime.Caller(1)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
// TestGet is a sample to run an endpoint test
func TestGet(t *testing.T) {
r, _ := http.NewRequest("GET", "/my/endpoint/fetches/data", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
}
When i run using go test -v ,
I get in response dial tcp :0: getsockopt: connection refused
I am using MariaDB running on my local,
I have verified using netstat -tulpn that my database is running perfectly fine (I get a valid response if i use postman and my server is running)
One weird observation , after inclusion of line _ "golife-api-cons/routers" i get this error even before test's are ran
My test passes with response 200 OK , but without any data as i get in response the above mentioned error
EDIT
The default path by used by TestBeegoInit function used is /path/to/my/project/test
which is not the desired path , so i tried giving the absolute path too , still i am not able to connect DB.
After much trying I came to know that beego initializes its variable called as AppPath in beego/conf.go like -
AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
when you run your tests you run them with go test -v
but as a result the os.Args[0] is the text executable which will be /tmp/path/to/test and not path/to/app/exe
hence as a result it does not find config/app.conf which is in your app path which has db connection details.
Responsible line in beego/conf.go -
appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
This all happens in beego's init function when you say
import (
"github.com/astaxie/beego"
_ "path/to/routers"
)
Hack for this is -
create a new package / file with init function which looks has -
package common
import (
"os"
"strings"
)
func init() {
cwd := os.Getenv("PWD")
rootDir := strings.Split(cwd, "tests/")
os.Args[0] = rootDir[0] // path to you dir
}
here you are changing os.Args[0] and assigning your directory path
make sure you import it before beego so now import will look like
import (
_ "path/to/common"
"github.com/astaxie/beego"
_ "path/to/routers"
)
And finally you connect to DB !
You are initializing your app as
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
Where file is the caller file.
TestBeegoInit is:
func TestBeegoInit(ap string) {
os.Setenv("BEEGO_RUNMODE", "test")
appConfigPath = filepath.Join(ap, "conf", "app.conf")
os.Chdir(ap)
initBeforeHTTPRun()
}
hence the location where your tests are looking for configuration is
<this_file>/../conf/app.conf
which basically is the default config file.
Basically you are not able to connect to the database. Perhaps because you are unknowingly connecting to your default database for the tests too. I suspect this is not what you are trying to do.
Short: How can I read the CGI var REMOTE_USER on golang using fastcgi?
Long:
I'm trying to write a program in go to work behind a httpd using fcgi over a socket. The httpd does the ssl termination and provides basic auth. I need to read $REMOTE_USER, but I cannot in golang, while I can in perl.
My code is based on this fcgi example. I try
func homeView(w http.ResponseWriter, r *http.Request) {
user, pass, authok := r.BasicAuth()
But authok is always false, user and pass remain empty, although I know for sure that the authorization (done by httpd) was OK. To eliminate other errors, I have done it in perl:
my $socket = FCGI::OpenSocket("/run/fcgi-check.sock", 5);
my $q = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
while ($q->Accept() >= 0) {
my $c = CGI::Simple->new;
my $user_id = $c->remote_user();
and it works fine in perl.
To debug, I printed the output of r.Header and I got:
map[Authorization:[]
Am I right that the header that go sees does no hold any information about any authorization? But it does in perl.
Here is a full but minimal golang code example that demonstrates the problem (on OpenBSD 5.8 with go version go1.4.2 openbsd/amd64 and OpenBSDs httpd with 'authenticate "/" with restricted_users' in httpd.conf.
package main
import (
"github.com/gorilla/mux"
"io"
"log"
"fmt"
"net"
"net/http"
"net/http/fcgi"
)
func homeView(w http.ResponseWriter, r *http.Request) {
headers := w.Header()
headers.Add("Content-Type", "text/html")
headers.Add("Cache-Control", "no-cache, no-store, must-revalidate")
headers.Add("Pragma", "no-cache")
headers.Add("Expires", "0")
r.ParseForm()
user, pass, authok := r.BasicAuth()
if authok {
io.WriteString(w, fmt.Sprintln("Auth OK"))
io.WriteString(w, fmt.Sprintln("user is: "+user+", pass is: "+pass))
} else {
io.WriteString(w, fmt.Sprintln("Auth NOT OK"))
}
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/check/", homeView)
var err error
listener, err := net.Listen("unix", "/run/fcgi-check.sock")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
err = fcgi.Serve(listener, r)
if err != nil { log.Fatal(err)}
}
Help will be appreciated!
Thanks in advance!
T.
Go 1.9 will expose cgi environment variables. As seen in this closed ticket:
https://go-review.googlesource.com/c/40012
The simple answer (as of go version 1.4.2) is that go currently does not support the transfer of CGI variable REMOTE_USER.
While #JimB is correct on that you're wrong in your approach, I'll answer the question as stated.
The net/http/fcgi package uses the machinery of net/http/cgi to populate an instance of http.Request—which is passed to your handler—with "parameters" (key/value pairs) submitted by the webserver during the FastCGI session (call).
This is done here.
Now if you'll inspect the relevant bit of the net/http/cgi code, you'll see that the variables which are not mapped to specific dedicated fields of http.Request get converted to HTTP "headers".
This means, your code should be able to access the variable you need using something like
ruser := r.Header.Get("Remote-User")
Update 2015-12-02: the reseach performed by #JimB and the OP showed that there's apparently no way to read the REMOTE_USER variable under FastCGI. Sorry for the noise.
This core change to the fcgi package is in review and is close to being merged. If it's no longer relevant to you, hopefully it will be useful to others.