As an exercise I created a small HTTP server that generates random game mechanics, similar to this one. I wrote it on a Windows 7 (32-bit) system and it works flawlessly. However, when I run it on my home machine, Windows 7 (64-bit), it always fails with the same message: exit status -1073741819. I haven't managed to find anything on the web which references that status code, so I don't know how important it is.
Here's code for the server, with redundancy abridged:
package main
import (
"fmt"
"math/rand"
"time"
"net/http"
"html/template"
)
// Info about a game mechanic
type MechanicInfo struct { Name, Desc string }
// Print a mechanic as a string
func (m MechanicInfo) String() string {
return fmt.Sprintf("%s: %s", m.Name, m.Desc)
}
// A possible game mechanic
var (
UnkillableObjects = &MechanicInfo{"Avoiding Unkillable Objects",
"There are objects that the player cannot touch. These are different from normal enemies because they cannot be destroyed or moved."}
//...
Race = &MechanicInfo{"Race",
"The player must reach a place before the opponent does. Like \"Timed\" except the enemy as a \"timer\" can be slowed down by the player's actions, or there may be multiple enemies being raced against."}
)
// Slice containing all game mechanics
var GameMechanics []*MechanicInfo
// Pseudorandom number generator
var prng *rand.Rand
// Get a random mechanic
func RandMechanic() *MechanicInfo {
i := prng.Intn(len(GameMechanics))
return GameMechanics[i]
}
// Initialize the package
func init() {
prng = rand.New(rand.NewSource(time.Now().Unix()))
GameMechanics = make([]*MechanicInfo, 34)
GameMechanics[0] = UnkillableObjects
//...
GameMechanics[33] = Race
}
// serving
var index = template.Must(template.ParseFiles(
"templates/_base.html",
"templates/index.html",
))
func randMechHandler(w http.ResponseWriter, req *http.Request) {
mechanics := [3]*MechanicInfo{RandMechanic(), RandMechanic(), RandMechanic()}
if err := index.Execute(w, mechanics); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", randMechHandler)
if err := http.ListenAndServe(":80", nil); err != nil {
panic(err)
}
}
In addition, the unabridged code, the _base.html template, and the index.html template.
What could be causing this issue? Is there a process for debugging a cryptic exit status like this?
When I ran it, I got the following two errors:
template: content:6: nil pointer evaluating *main.MechanicInfo.Name
http: multiple response.WriteHeader calls
The former was in the web browser, the latter in the console window where I launched your server.
The nil pointer problem is because your abridged program leaves GameMechanics[1:32] set to nil.
The second error is interesting. The only place in your program that any methods on your http.ResponseWriter get called is inside of index.Execute, which is not your code -- meaning maybe there is something wrong happening in html/template. I'm testing this with Go 1.0.2.
I put _base.html at the top of index.html and then changed index to this:
var index = template.Must(template.ParseFiles("templates/index.html"))
and the http.WriteHeaders warning went away.
Not really an answer, but a direction you could explore.
As a bonus, here's the more "Go way" of writing your program. Note that I simplified the use of the PRNG (you don't need to instantiate unless you want several going in parallel) and simplified the structure initializer:
package main
import (
"fmt"
"html/template"
"math/rand"
"net/http"
)
// Info about a game mechanic
type MechanicInfo struct{ Name, Desc string }
// Print a mechanic as a string
func (m MechanicInfo) String() string {
return fmt.Sprintf("%s: %s", m.Name, m.Desc)
}
// The game mechanics
var GameMechanics = [...]*MechanicInfo{
{"Avoiding Unkillable Objects",
"There are objects that the player cannot touch. These are different from normal enemies because they cannot be destroyed or moved."},
{"Race",
"The player must reach a place before the opponent does. Like \"Timed\" except the enemy as a \"timer\" can be slowed down by the player's actions, or there may be multiple enemies being raced against."},
}
// Get a random mechanic
func RandMechanic() *MechanicInfo {
i := rand.Intn(len(GameMechanics))
return GameMechanics[i]
}
var index = template.Must(template.ParseFiles("templates/index.html"))
func randMechHandler(w http.ResponseWriter, req *http.Request) {
mechanics := [3]*MechanicInfo{RandMechanic(), RandMechanic(), RandMechanic()}
if err := index.Execute(w, mechanics); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", randMechHandler)
if err := http.ListenAndServe(":80", nil); err != nil {
panic(err)
}
}
Related
As I know, every requests to the server creates new goroutine. For ex (probably incorrect code, but this topic is not about it):
package main
import "net/http"
var exampleMap map[string]string
func handlerPost(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
{
exampleMap["test"] = test // Must I syncrhonise this writing?
}
case "GET":
{
if v, ok := exampleMap["test"] { // And what about reading?
fmt.Println(v)
}
}
}
}
func main() {
http.HandleFunc("/", handlerPost)
http.ListenAndServe(":8080", nil)
}
Does it mean that its unsafe to do it like this and I have to use sync.Map (for example), and what about if instead map here was a database queries? What can I do in this case. Thank you!
exampleMap is shared among goroutines, so you have to synchronize access to it. A mutex would do, a RWMutex would perform better:
var exampleMap map[string]string
var exampleMutex sync.RWMutex
...
exampleMutex.Lock()
exampleMap["test"] = test
exampleMutex.Unlock()
...
exampleMutex.RLock()
v, ok := exampleMap["test"]
exampleMutex.RUnlock()
if ok {
...
}
I'm not able to get all the keys from Gin's Context.Header (Golang's gin-gonic http/rest framework) field, even though Header is defined as a Map "type Header map[string][]string" (Header is from net\http\Header.go, request is from net\hhtp\request.go, Context is from Gin-gonic's package), and surprisingly it's strange that even at the compile/build time, Visual Studio code doesn't let me call/use "MapKeys()" method on this Header which is of map type (Given Golang is statically typed language and it knows its data type at compile time already).
I need to copy all the HTTP headers into the Logger, so that when I log any message, I can put the corresponding request Headers.
And also I need to pass all the HTTP Headers from HTTP to gRPC calls for end to end call traceability need.
func (l *Logger) InfoCtx(ctx *gin.Context, md metadata.MD) *zerolog.Event {
headerName := "X-Request-Id" // Read all the headers from the ENV file
// mapping := make(map[string]string)
// mapping[headerName] = ctx.Request.Header[headerName][0]
event := l.Logger.Info()
// ctx.Request.Header ==> Even though this is a "map" type,
// which is known at the compilation time itself,
// it doesn't let me use any map functions.
if ctx != nil && len(ctx.Request.Header[headerName]) > 0 {
event = event.Str(headerName, ctx.Request.Header[headerName][0])
} else if md != nil {
// some other gRPC metadata context handling (not relevant for this question)
}
return event
}
Could you please help?
Header Object
Request object uses Header field
Shows Header is of map type
I may be misunderstanding your issue but I'm able to enumerate the map of request headers from Gin's context:
go.mod:
module github.com/OWNER/stackoverflow/69315290
go 1.16
require github.com/gin-gonic/gin v1.7.4
And main.go:
package main
import (
"log"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
for k, v := range c.Request.Header {
log.Printf("%s: %v", k, v)
}
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run()
}
And:
curl --header "dog: freddie" localhost:8080/ping
Yields:
{"message":"pong"}
And:
2021/09/25 10:41:05 User-Agent: [curl/7.68.0]
2021/09/25 10:41:05 Accept: [*/*]
2021/09/25 10:41:05 Dog: [freddie]
[GIN] 2021/09/25 - 10:41:05 | 200 | 408.631µs | 127.0.0.1 | GET "/ping"
The other approach that worked for me meanwhile was,
I created a struct to have "HttpHeadersMap map[string][]string" in it
type CommonContext struct {
HttpHeadersMap map[string][]string
RequestContext context.Context
GrpcMDHeadersMap map[string][]string
}
Assigned Gin's "ctx.Request.Header" to "HttpHeadersMap map[string][]string"
func GetCommonCtx(ctx *gin.Context, md metadata.MD) CommonContext {
var commonContext CommonContext
if ctx != nil {
// event = event.Str(headerName, ctx.Request.Header[headerName][0])
commonContext = CommonContext{ // don't return address, use valye type
HttpHeadersMap: ctx.Request.Header,
RequestContext: ctx.Request.Context(),
}
}
...
}
then inside "gRPC Interceptor (just showing for example use case)", I could use it "HttpHeadersMap" regular way as "headersMapVal.MapKeys()" to iterate over the Map keys.
func clientInterceptor(
ctx context.Context,
method string,
req interface{},
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
start := time.Now()
commonCtx := commonContext.GetCommonCtx(nil, metadata.MD{})
if callOpt, ok := opts[0].(CustomDataCallOption); ok {
headersMapVal := reflect.ValueOf(callOpt).FieldByName("HeadersMap")
newMap := make(map[string]string)
// allKeysMap := make(map[string]string)
for _, key := range headersMapVal.MapKeys() {
// fmt.Printf("headersMapVal.MapKeys(), e %v", e)
// c_key := e.Convert(headersMapValueIndirectStr.Type().Key())
keyValue := headersMapVal.MapIndex(key)
...
...
}
I'm trying to use the GetRawInputDeviceList function in Go and I keep getting the following error:
The parameter is incorrect.
Per the official documentation: the first parameter needs to be an array of RAWINPUTDEVICELIST structures for the devices attached to the system. I don't quite understand what combination of unsafe.Pointer, pointer arithmetic(?), and other things I need to do in order to get this to work correctly.
I found this Medium article that offers some guidance, but it's not directly applicable to my use case. I don't have enough experience working with pointers and manual memory management to apply it to my problem. I don't know how to translate this C++ example to Go, and I got so desperate that I tried to convert a working VBA solution to Go with no success.
I have two questions regarding this matter:
How do I convert an array of structs in Go to the appropriate type expected for a Windows API call?
How do I convert the result of the Windows API call back to an array of structs with populated data?
Environment
Here's my system/language details:
macOS Mojave v10.14.6
Go v1.10.7 (required to run executables on Windows XP)
I'm targeting Windows XP, so I run the following command to compile it:
env GOOS=windows GOARCH=386 go1.10.7 build -o example.exe example.go
Code
Here's the code I'm trying to get working. I'm not doing anything with devices yet, but the goal would be to use the handle (DeviceHandle from rawInputDeviceList) to get information about the input device.
package main
import (
"fmt"
"syscall"
"unsafe"
)
// RAWINPUTDEVICELIST structure
type rawInputDeviceList struct {
DeviceHandle uintptr
Type uint32
}
var (
user32 = syscall.NewLazyDLL("user32.dll")
getRawInputDeviceListProc = user32.NewProc("GetRawInputDeviceList")
)
func main() {
dl := rawInputDeviceList{}
size := uint32(unsafe.Sizeof(dl))
// First I determine how many input devices are on the system, which
// gets assigned to `devCount`
var devCount uint32
_ = getRawInputDeviceList(nil, &devCount, size)
if devCount > 0 {
size = size * devCount
devices := make([]rawInputDeviceList, size) // <- This is definitely wrong
for i := 0; i < int(devCount); i++ {
devices[i] = rawInputDeviceList{}
}
// Here is where I get the "The parameter is incorrect." error:
err := getRawInputDeviceList(&devices, &devCount, size)
if err != nil {
fmt.Printf("Error: %v", err)
}
}
}
// Enumerates the raw input devices attached to the system.
func getRawInputDeviceList(
rawInputDeviceList *[]rawInputDeviceList, // <- This is probably wrong
numDevices *uint32,
size uint32,
) error {
_, _, err := getRawInputDeviceListProc.Call(
uintptr(unsafe.Pointer(rawInputDeviceList)),
uintptr(unsafe.Pointer(numDevices)),
uintptr(size))
if err != syscall.Errno(0) {
return err
}
return nil
}
First, the ERROR_INVALID_PARAMETER error is cause by the last parameter: cbSize, According to the document, it should always be set to size of RAWINPUTDEVICELIST.
Then you will pass the compiler but still get the runtime error. because you have passed a pointer of array.
The following code works for me:
package main
import (
"fmt"
"syscall"
"unsafe"
)
// RAWINPUTDEVICELIST structure
type rawInputDeviceList struct {
DeviceHandle uintptr
Type uint32
}
var (
user32 = syscall.NewLazyDLL("user32.dll")
getRawInputDeviceListProc = user32.NewProc("GetRawInputDeviceList")
)
func main() {
dl := rawInputDeviceList{}
size := uint32(unsafe.Sizeof(dl))
// First I determine how many input devices are on the system, which
// gets assigned to `devCount`
var devCount uint32
_ = getRawInputDeviceList(nil, &devCount, size)
if devCount > 0 {
devices := make([]rawInputDeviceList, size * devCount) // <- This is definitely wrong
for i := 0; i < int(devCount); i++ {
devices[i] = rawInputDeviceList{}
}
// Here is where I get the "The parameter is incorrect." error:
err := getRawInputDeviceList(&devices[0], &devCount, size)
if err != nil {
fmt.Printf("Error: %v", err)
}
for i := 0; i < int(devCount); i++ {
fmt.Printf("Type: %v", devices[i].Type)
}
}
}
// Enumerates the raw input devices attached to the system.
func getRawInputDeviceList(
rawInputDeviceList *rawInputDeviceList, // <- This is probably wrong
numDevices *uint32,
size uint32,
) error {
_, _, err := getRawInputDeviceListProc.Call(
uintptr(unsafe.Pointer(rawInputDeviceList)),
uintptr(unsafe.Pointer(numDevices)),
uintptr(size))
if err != syscall.Errno(0) {
return err
}
return nil
}
I am learning Go and decided to rewrite a MQTT orchestrator which I originally wrote in Python. The very basic part works fine:
package main
import (
"fmt"
"time"
"os"
MQTT "github.com/eclipse/paho.mqtt.golang"
log "github.com/sirupsen/logrus"
)
// definitions for a switch
type Switch struct {
topic string
state int
}
func allEvents(client MQTT.Client, msg MQTT.Message) {
log.WithFields(log.Fields{"topic": msg.Topic(), "payload": fmt.Sprintf("%s", msg.Payload())}).Info()
}
func initMQTT() MQTT.Client {
opts := MQTT.NewClientOptions()
opts.AddBroker("tcp://mqtt.example.com:1883")
opts.SetClientID("go-dispatcher")
opts.SetCleanSession(true)
client := MQTT.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
log.Info("connected to MQTT broker")
return client
}
func main() {
// this is that part I want to modify later in the question
c := initMQTT()
if token := c.Subscribe("#", 0, allEvents); token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
os.Exit(1)
}
time.Sleep(100000 * time.Hour)
}
Having used pointers in a distant past with C, I wanted to modify the program to pass, in the initialization part, the client by reference (more as a learning experience, the first code looks better to me)
package main
import (
"fmt"
"time"
"os"
MQTT "github.com/eclipse/paho.mqtt.golang"
log "github.com/sirupsen/logrus"
)
// definitions for a switch
type Switch struct {
topic string
state int
}
func allEvents(client MQTT.Client, msg MQTT.Message) {
log.WithFields(log.Fields{"topic": msg.Topic(), "payload": fmt.Sprintf("%s", msg.Payload())}).Info()
}
// this time we get a pointer and do not return anything
func initMQTT(client *MQTT.Client) {
opts := MQTT.NewClientOptions()
opts.AddBroker("tcp://mqtt.example.com:1883")
opts.SetClientID("go-dispatcher")
opts.SetCleanSession(true)
client = MQTT.NewClient(opts)
if token := *client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
log.Info("connected to MQTT broker")
}
func main() {
// the client is defined in main()
var c MQTT.Client
// and passed by reference so that the function modifies it
initMQTT(&c)
if token := c.Subscribe("#", 0, allEvents); token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
os.Exit(1)
}
time.Sleep(100000 * time.Hour)
}
It fails to compile with
# command-line-arguments
.\main.go:29:9: cannot use mqtt.NewClient(opts) (type mqtt.Client) as type *mqtt.Client in assignment:
*mqtt.Client is pointer to interface, not interface
.\main.go:30:21: client.Connect undefined (type *mqtt.Client is pointer to interface, not interface)
Following advice form another question, I tried to remove & and * (blindly to start with, to tell the truth), and get a runtime error
time="2018-05-26T21:02:20+02:00" level=info msg="connected to MQTT broker"
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x604486]
goroutine 1 [running]:
main.main()
D:/Seafile/dev/Go/src/perso/domotique.dispatcher/main.go:39 +0x36
I though that since I defined c, I could just pass it as a reference but apparently the C-way is not the right one here? (it is usually in the examples I read)
This is a common misunderstanding. Because you've defined c as a value rather than a pointer type, you can't modify it without re-defining it.
The fact that you've passed its memory address does not enable you to modify it. This is different from a number of other languages.
I'm coding a ShareX clone for Linux in Go that uploads files and images to file sharing services through http POST requests.
I'm currently using http.Client and Do() to send my requests, but I'd like to be able to track the upload progress for bigger files that take up to a minute to upload.
The only way I can think of at the moment is manually opening a TCP connection on port 80 to the website and write the HTTP request in chunks, but I don't know if it would work on https sites and I'm not sure if it's the best way to do it.
Is there any other way to achieve this?
You can create your own io.Reader to wrap the actual reader and then you can output the progress each time Read is called.
Something along the lines of:
type ProgressReader struct {
io.Reader
Reporter func(r int64)
}
func (pr *ProgressReader) Read(p []byte) (n int, err error) {
n, err = pr.Reader.Read(p)
pr.Reporter(int64(n))
return
}
func main() {
file, _ := os.Open("/tmp/blah.go")
total := int64(0)
pr := &ProgressReader{file, func(r int64) {
total += r
if r > 0 {
fmt.Println("progress", r)
} else {
fmt.Println("done", r)
}
}}
io.Copy(ioutil.Discard, pr)
}
Wrap the reader passed as the request body with something that reports progress. For example,
type progressReporter struct {
r io.Reader
max int
sent int
}
func (pr *progressReader) Read(p []byte) (int, error) {
n, err := pr.r.Read(p)
pr.sent += n
if err == io.EOF {
pr.atEOF = true
}
pr.report()
return n, err
}
func (pr *progressReporter) report() {
fmt.Printf("sent %d of %d bytes\n", pr.sent, pr.max)
if pr.atEOF {
fmt.Println("DONE")
}
}
If previously you called
client.Post(u, contentType, r)
then change the code to
client.Post(u, contentType, &progressReader{r:r, max:max})
where max is the number of bytes you expect to send. Modify the progressReporter.report() method and add fields to progressReporter to meet your specific needs.