#Write json array to file

145 messages · Page 1 of 1 (latest)

atomic fulcrum
#

i have the entire pinging part

marble mauve
#

How are you storing this in the code?

#

If it's just a slice of structs, just pass the whole slice to json.Marshal

#

If it's not a slice of structs, make it into a slice of structs :)

atomic fulcrum
#

this is my code: ```go
type Response struct {
IP string json:"ip"
Timestamp string json:"timestamp"
Status string json:"status"
Last string json:"lastping"
}

func main() {
start := time.Now().UnixMilli()

fmt.Println("\n [ Start ] ")

content, err := ioutil.ReadFile("./servers.json")
if err != nil {
    log.Fatal("Error when opening file: ", err)
}

var servers []struct {
    IP string `json:"ip"`
    Port int `json:"port"`
}
err = json.Unmarshal(content, &servers)
if err != nil {
    log.Fatal("Error during Unmarshal(): ", err)
}


var pingout // idk what to put here
for i, data := range servers {
    res, err := PerformPing(data.IP, data.Port)
    if err != nil { fmt.Printf("[%d] (Failed) %s\n", i, err) }
    jsonString, _ := json.Marshal(res)
    pingout = append(pingout, jsonString)
}

final, _ := json.Marshal(pingout)
ioutil.WriteFile("ping_out.json", final, os.ModePerm)

fmt.Println("\n [ End ] ")
fmt.Printf("Took: %dms\n", time.Now().UnixMilli() - start)

}

marble mauve
#

var pingout []Response

atomic fulcrum
#

oh fromi PerformPing i get the Response struct back

#

Cannot use 'jsonString' (type []byte) as the type Response

marble mauve
#

Append the thing before marshaling

#

marshal in the end

atomic fulcrum
#

oh ok

#

makes sense i guess

marble mauve
#
var pingout []Response
for {
  pingout = append(pingout, res)
}
final, _ := json.Marshal(pingout)
atomic fulcrum
#

i get a pointer from PerformPing

#

panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x46e8ed]

#

nvm im stupid

#

the ping failed so ofc im getting nil

#

but im not skiping the rest of the loop

marble mauve
#

continue is your friend

atomic fulcrum
#

i just forgot the continue after it fails
if err != nil { fmt.Printf("[%d -> %s] (Failed) %s\n", i, data.IP, err); continue }

#

can i somehow make json.Marshal format the json data it gives me?

marble mauve
#

Like indent?

#

MarshalIndent is a thing i think

atomic fulcrum
marble mauve
#

MarshalIndent

atomic fulcrum
#

oh ok

#

i have another question

#

the pinging takes a bit of time

#

can i somehow run multiple pings at the same time?

#

because like this, 11 pings take 30secs

#

and thats quite a long time

marble mauve
#

I recommend doing the go tour about this, lots of good examples

atomic fulcrum
#

sounds interesting

marble mauve
atomic fulcrum
#

thank you for your help

#

i got a small problem

#

(i think)

#

nvm

#

forgot to add group.Wait()

#

i may have a problem

#

panic: runtime error: slice bounds out of range [-3:]

marble mauve
#

That's a panic, runtime error. yep, definitely looks like an error.

#

I bet some code caused this

atomic fulcrum
#

it seems to be some library im using

#
goroutine 16 [running]:
github.com/dreamscached/minequery/v2.(*Pinger).ping17ReadStatusResponsePacketPayload(0xc0000564a0?, {0x22c6c08c278, 0xc007740268})
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1841 +0x525
github.com/dreamscached/minequery/v2.(*Pinger).Ping17(0xc0000564a0, {0xc000361d72, 0xd}, 0x0?)
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1757 +0x27b
github.com/dreamscached/minequery/v2.Ping17(...)
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1731
main.main.func1({{0xc000361d72, 0xd}, {0xc000361d80, 0xa}, {0xc00036c100, 0x1, 0x4}}, 0x0?)
        F:/programming/2022/go/server_pinger/main.go:53 +0xe6
created by main.main
        F:/programming/2022/go/server_pinger/main.go:50 +0x608
exit status 2
marble mauve
#

Look at the line numbers to know what line caused

atomic fulcrum
#

in my main.go file or in the library files?

marble mauve
#

Well first in your file

atomic fulcrum
#

because the lines in my main.go file is in my PerformPing function

#
pingres, err := minequery.Ping17(data.IP, data.Port)
marble mauve
#

Looks like it's in the library, maybe it's not meant to handle concurency

#

Maybe you need a sperate pinger for each site, idk

#

Can't remote-debug it

atomic fulcrum
#

the library doesnt use panic and my code doesnt eighter

marble mauve
#

It looks like something is trying to access a slice index that doesn't exist

#

Which causes a panic

atomic fulcrum
#

the last line the error gives me is this: ```
pb.Write(lb[ln-lr.Len() : ln])

marble mauve
#

¯_(ツ)_/¯

#

len-lr.Len() seems to come out as negative

#

So panic

atomic fulcrum
#

thats the line in the library

marble mauve
#

You can open an issue there

atomic fulcrum
#

can i somehow "skip" the panic with something like a try {} except () {}?

marble mauve
#

There's recover not best practice

#

If this didn't happen when you were doing the requests 1 by 1, maybe the problem is with concurrency, did you try making a separate pinger for each site?

atomic fulcrum
#

if i run with the "threads" (idk what to call it) it works on smaller scale like 10 requests

#

but when i go trough my entire list it fails

marble mauve
#

fails?

atomic fulcrum
#

with the panic from before

marble mauve
#

I dunno, can open issue at the library

#

Or try researching recover and hack something together

atomic fulcrum
#

can i count how many times i recover from a panic?

violet owl
#

You could do that (although it would be a bit hacky) by wrapping the function that panics in an anonymous function that defers a function that recovers and then, if the recover does not return nil, increments a counter using a closure

#

nevermind

#

its just a bad idea

atomic fulcrum
#

i think using coroutines wasnt the best idea

violet owl
#

you could most likely implement this, but you shuld find another solution if possible

atomic fulcrum
#

because i get a lot of i/o timeouts, Couldnt establish connections and could not read response packets

violet owl
#

Couldnt you just have a simple wrapper for what you are doing that converts panics to regular errors and then just write the code "normally"

atomic fulcrum
#

uh can i print something and then remove that print in the next print call, like print("\rsomething", end="\r") in python?

violet owl
atomic fulcrum
violet owl
#

so you pass the list of addressees to the library and then it panics?

atomic fulcrum
#

basically

#

but the library has no panics

violet owl
#

what

#

What is the output you are getting

atomic fulcrum
#

the library has no panics in its code

#

and my code uses no panics

violet owl
#

thats not how that works

#

there is intrinsic panic

#

the library also may have imports

#

that can have panics

atomic fulcrum
violet owl
#

can you give a full stacktrace

atomic fulcrum
#
// Read entire packet to a buffer
pb := bytes.NewBuffer(make([]byte, 0, pl))
pb.Write(lb[ln-lr.Len() : ln]) // < panic here
if _, err = io.CopyN(pb, reader, int64(pl)-int64(lr.Len())); err != nil {
    return nil, err
atomic fulcrum
#
panic: runtime error: slice bounds out of range [-1:]

goroutine 454 [running]:
github.com/dreamscached/minequery/v2.(*Pinger).ping17ReadStatusResponsePacketPayload(0xc0000564a0?, {0x2785faece38, 0xc0076cc518})
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1841 +0x525
github.com/dreamscached/minequery/v2.(*Pinger).Ping17(0xc0000564a0, {0xc00045e1e0, 0xf}, 0x0?)
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1757 +0x27b
github.com/dreamscached/minequery/v2.Ping17(...)
        C:/Users/Sandbox/go/pkg/mod/github.com/dreamscached/minequery/[email protected]/ping_17.go:1731
main.main.func1({{0xc00045e1e0, 0xf}, {0xc00045e1f0, 0xa}, {0xc00045d100, 0x1, 0x4}}, 0x0?)
        F:/programming/2022/go/server_pinger/main.go:53 +0xe6
created by main.main
        F:/programming/2022/go/server_pinger/main.go:50 +0x608
exit status 2
violet owl
#

i am pretty confident this is simply a bug in the library

#

this looks like a lack of fault tolerance

#

Apprently in this case 'ln' is zero while 'lr' is 1, which seems like a case the author simlpy missed

#

leading to this weird negative index slicing operation

#

This is extremely weird though, since the buffer at the beginning 'lb' is a constant size 5 buffer, therefore the implementation of the concrete io.Reader used here must be wrong. Since a read from an io.Reader that did not return an error should return the correct number of elements read, the number of elements read is clearly zero here though, which should not be possible

violet owl
atomic fulcrum
violet owl
#

Can you explain how you are using goroutines?

atomic fulcrum
violet owl
#

they allow you to aynchronously run some functions using the go keyword

atomic fulcrum
#

oh so go func right?

violet owl
#

can you maybe post your current source?

violet owl
atomic fulcrum
#

if yes, ```go
go func(data Data, i int) {
// my getting daat code
}(data, i)

#

this: ```go
go func(data Data, i int) {
defer wg.Done()

res, err := PerformPing(data.IP, data.Ports[0].Port)
if err != nil { fmt.Printf("[%d -> %s] (Failed) %s\n", i, data.IP, err); return }
pingout = append(pingout, *res)
}(data, i)

violet owl
#

It would be easier if you posted your source

atomic fulcrum
# violet owl It would be easier if you posted your source

k: ```go
package main

type Data struct {
IP string json:"ip"
Timestamp string json:"timestamp"
Ports []struct {
Port int json:"port"
Proto string json:"proto"
Status string json:"status"
Reason string json:"reason"
TTL int json:"ttl"
} json:"ports"
}

type Result struct {
IP string
VersionName string
ProtocolVersion int
OnlinePlayers int
MaxPlayers int
Description Chat17 // type Chat17 interface{} from minequery
Icon image.Image
}

func PerformPing(IP string, Port int) Result {
pingres := minequery.Ping17(IP, Port)

res := Reuslt {
    IP,
    pingres.VersionName,
    pingres.ProtocolVersion,
    pingres.OnlinePlayers,
    pingres.MaxPlayers,
    pingres.Description,
    pingres.Icon,
}

return res

}

func main() {
start := time.Now().UnixMilli()

fmt.Println("\n [ Start ] ")

content, err := ioutil.ReadFile("./server_dump.json")
if err != nil {
    log.Fatal("Error when opening file: ", err)
}

var payload []Data
err = json.Unmarshal(content, &payload)
if err != nil {
    log.Fatal("Error during Unmarshal(): ", err)
}


var wg sync.WaitGroup
var pingout []Result
for i, data := range payload {
    wg.Add(1)

    go func(data Data, i int) {
        defer wg.Done()

        res, err := PerformPing(data.IP, data.Ports[0].Port)
        if err != nil { fmt.Printf("[%d -> %s] (Failed) %s\n", i, data.IP, err); return }
        pingout = append(pingout, *res)
    }(data, i)
}
wg.Wait()

final, _ := json.MarshalIndent(pingout, "", "  ")
err = ioutil.WriteFile("ping_out.json", final, os.ModePerm)
if err != nil { fmt.Printf("(Error -> ioutil.WriteFile) %s\n", err) }

fmt.Println("\n [ End ] ")
fmt.Printf("Took: %dms\n", time.Now().UnixMilli() - start)

}

#

(removed the imports because the messave would've been too long)

#

(also the code is really bad)

violet owl
#

alright, could you start by just removing the goroutines

atomic fulcrum
#

but without them there is no panic

violet owl
#

alright then the library is not thread safe

#

i assume that io.Reader they were using has a threading bug

atomic fulcrum
#
var panics int

func wrapAndCountPanics(f func()) {
    defer func() {
        if r := recover(); r != nil {
            panics++
        }
    }()
    f()
}

// ...

// for
go wrapAndCountPanics(func() {
    defer wg.Done()

    res, err := minequery.Ping17(data.IP, data.Ports[0].Port)
    if err != nil { fmt.Printf("[%d -> %s] (Failed) %s\n", i, data.IP, err); return }
    pingout = append(pingout, *res)
})

if panics > 5 {
    panic("More than 5 panics\nexiting") // never gets called
}
violet owl
#

i would strongly recommend not using this

atomic fulcrum
#

there are never more than 5 panics
i think its probably just the one

violet owl
#

you should look for a different library that is thread safe

atomic fulcrum
#

if i print the panics variable at the end, it gives me 1

#

so i think its just some weird server response

violet owl
#

i dont think so, this will most likely give you wrong outputs

atomic fulcrum
#

why?

violet owl
#

the reader panics are most likely not because of a response but because of threading issues

atomic fulcrum
#

but if it only happens once i can just ignore it, right?

#

because im checking ca 2.5k servers

violet owl
#

it might happen in the 'wrong' thread

#

so the result might be wrong

atomic fulcrum
#

h.... a...

violet owl
#

i am sorry but i dont have the time to explain multithreading right now

atomic fulcrum
#

ok