Go-zabbix library does not find existing Event by id - go

I am trying to get an Event with a given event_id from Zabbix via the library github.com/cavaliercoder/go-zabbix.
An event with this id exists and is currently active. Connection to Zabbix is successful. Moreover, if I remove the EventIDs filter, it finds more than 600 events. But (!) I cannot access some of them directly from the Zabbix web interface under the same user.
Code:
session, err := zabbix.NewSession("zabbix_url/api_jsonrpc.php", "user", "password")
if err != nil {
panic(err)
}
var event_ids []string = []string{"2589270"}
params := zabbix.EventGetParams{
EventIDs: event_ids,
}
events, err := session.GetEvents(params)
fmt.Println(events)
Output:
[]
Errors:
2021/07/06 18:49:09 Error getting events: No results were found matching the given search
parameters
2021/07/06 18:49:09 No events found
2021/07/06 18:49:09 Validated 0 Events
Maybe I somehow incorrectly enter the id in the library?
In the source code of the library, the EventIDs parameter looks like this:
EventIDs []string `json:"eventids,omitempty"`
At the same time, everything works correctly from curl.
UPD
Code:
jparams, err := json.Marshal(params)
os.Stdout.Write(jparams)
Returns:
{"eventids":["2589270"],"object":0,"acknowledged":false}
UPD2:
It has been empirically established that the problem lies in the acknowledged parameter. If it is set to false, the event is not found. If it is set to true, the event is found. Curl exhibits the same behavior.
The problem is that the acknowledged parameter is set by default to either true or false. And I cannot remove it.
As planned by zabbix api (I guess), if this parameter is set to false, all events should be returned. If the parameter is set to true, then only acknowledged events should be returned. But it doesn't work as intended.

Related

Whatsmeow conversation data [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
I'm trying to build a tui client for WhatsApp using whatsmeow.
After half a day of searching and reading through the docs, I still can't find a way to get the conversation data of individual contacts. Any help is appreciated.
I found ParseWebMessage but I'm not really sure how to use this.
chatJID, err := types.ParseJID(conv.GetId())
for _, historyMsg := range conv.GetMessages() {
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
yourNormalEventHandler(evt)
}
Matter of fact I'm not even sure if this is what I'm looking for
Well, you basically linked to the part of the docs that contains the information you're looking for. The return type of the ParseWebMessage call is events.Message, documented here. It contains an Info field of type MessageInfo (again, documented here). In turn, this MessageInfo type embeds the MessageSource type see docs here which looks like this:
type MessageSource struct {
Chat JID // The chat where the message was sent.
Sender JID // The user who sent the message.
IsFromMe bool // Whether the message was sent by the current user instead of someone else.
IsGroup bool // Whether the chat is a group chat or broadcast list.
// When sending a read receipt to a broadcast list message, the Chat is the broadcast list
// and Sender is you, so this field contains the recipient of the read receipt.
BroadcastListOwner JID
}
So to get the contact who sent a given message, given your code evt, err := cli.ParseWebMessage(), you need to check:
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
if err != nil {
// handle error, of course
}
fmt.Printf("Sender ID: %s\nSent in Chat: %s\n", evt.Info.Sender, evt.Info.Chat)
if evt.Info.IsGroup {
fmt.Printf("%s is a group chat\n", evt.Info.Chat)
}
You can also skip messages you sent by simply doing this:
if evt.Info.IsFromMe {
continue
}
The evt.Info.Chat and evt.Info.Sender fields are all of type JID, documented here. There essentially are 2 variations of this ID type: user and server JID's and AD-JIDs (user, agent, and device). You can distinguish between the two by checking the JID.AD flag.
I haven't used this module at all, I only scanned through the docs briefly, but as I understand it, this module allows you to write a handler which will receive an events.Message type for everything you receive. By checking the evt.Info.IsGroup, you can work out whether the message we sent in a group chat, or in your person-to-person conversation thing. Based on evt.Info.Sender and evt.Info.Chat, you can work out who sent the message. The evt.Info.Sender being a JID in turn allows you to call the GetUserInfo method, passing in the JID, which gets you a UserInfo object in return as documented here, showing the name, picture, status, etc...
So I guess you're looking for something along these lines:
// some map of all messages from a given person, sent directly to you
contacts := cli.GetAllContacts() // returns map[JID]ContactInfo
personMsg := map[string][]*events.Message
evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
if err != nil {
// handle
}
if !evt.Info.IsFromMe && !evt.Info.IsGroup {// not a group, not sent by me
info, _ := cli.GetUserInfo([]types.JID{evt.Info.Sender})
if contact, ok := contacts[info[evt.Info.Sender]; ok {
msgs, ok := personMsg[contact.PushName]
if !ok {
msgs := []*events.Message{}
}
personMsg[contact.PushName] = append(msgs, evt)
}
}
Note the ContatInfo type didn't show up in the docs right away, but I stumbled across it in the repo.
Either way, I'm not quite sure what you're trying to do, and how/why you're stuck. All it took to find this information was to check the return type of the ParseWebMessage method you mentioned, check a couple of types, and scroll through some of the listed/documented methods to get a rough idea of how you can get all the data you could possibly need...

Fetching new Gmail emails after a timestamp

I am going through Gmail API docs(https://developers.google.com/gmail/api), I am able to read all the user emails which are present in the inbox.
eg snippet (reading complete list of emails):
for {
req := svc.Users.Messages.List("me")
r, _ := req.Do()
for _, m := range r.Messages {
msg, _ := svc.Users.Messages.Get("me", m.Id).Do()
date := ""
for _, h := range msg.Payload.Headers {
if h.Name == "Date" {
date = h.Value
break
}
}
msgs = append(msgs, message{
...
})
}
}
Now, when new emails come I want to read them as well (either immediately or after some time). I can write a scheduled job for that purpose, But I am not sure if I can fetch email after a particular timestamp or after an email identifier. I don't want to read a whole bunch of emails, again and again, to figure out the new emails, in this way, there is a lot of unnecessary computation being involved. Is there any way I can make this task easier?
Looking at the docs, it looks like it supports a query parameter, q.
The query parameter supports the same options as available in the Gmail search bar:
Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, "from:someuser#example.com rfc822msgid:somemsgid#example.com is:unread". Parameter cannot be used when accessing the api using the gmail.metadata scope.
This means you can do something like "after:YYYY/MM/DD" or with a timestamp "after:1616819452".
req := svc.Users.Messages.List("me").Q("after:2021/01/01")
See the full usage here https://pkg.go.dev/google.golang.org/api/gmail/v1#UsersMessagesListCall.Q

NextPageToken gives invalid input error, 400 - Google Directory API ChomeDevices

I have to fetch 250K chromebooks from google workspace (Gsuite), I am using Admin Directory API to retrieve JSON data from Google.
The response returns in chunks of 200 records, in the response is included a nextPageToken, I use that next page token to retrieve the next 200 and so on.
After an hour, of using the nextPageToken attached from the previous request, However Google returns with error 400,
{error_code: 400, "message"=>"Invalid Input: CMiJhq7-5ewCEp0BCm737N8GN......"},
Note: This string 'CMiJhq7-5ewCEp0BCm737N8GN......' which google is calling as invalid is the nextPageToken.
Why is this happening? Does nextPageToken expire after 1 hour?
My code snippet:
query_list = {
'maxResults' => 200,
'access_token' => access_token,
'pageToken' => next_page_token
}
HTTParty.get(endpoint_url, query: query_list)
The nextPage token is created when the initial request is sent. This token is used in order to get the next batch of rows from the request.
This token is intended to be used immediately as the data associated with the initial request may be changed if you wait to long.
So yes next page tokens do expire i would actually expect them to expire in a lot less than an hour. I also wonder if the next page token wouldn't just expire after you used it the first time.
If you want to make the same request again i suggest you do that and get new next page tokens built for you after the hour.
I had to change my approach, initially, I fetched 200 chunks from Google API, performed some time-taking processing and then made entries into my database (database-intensive tasks) and then requested the next 200 chunks and so so. After an hour, the last nextpagetoken sent by Google became invalid.
So, now I fetch 200 chunks, save them to my database in JSON format without performing any database-intensive tasks, request the next 200, and so on. I was able to fetch 300K Chromebooks JSON data from google in around 56 Minutes before the nextPageToken became invalid.
I am now processing that JSON data present in my database, without having network overhead or any google API dependency.
I'm encountering error Error 400: Invalid Value, invalid when I tried to use pageToken parameter of the Google Calendar Events API.
The code (in Go) I was using.
call := service.Events.List(calendarID).SingleEvents(true)
events, err := call.Do()
if err != nil {
return err
}
var allEvents []*calendar.Event
allEvents = append(allEvents, events.Items...)
if events.NextPageToken != "" {
nextPageToken := events.NextPageToken
nextCall := service.Events.List(calendarID).SingleEvents(true).PageToken(nextPageToken)
events, err = nextCall.Do()
if err != nil {
return err
}
allEvents = append(allEvents, events.Items...)
}
As illustrated in Paging through lists of resources, the next API call has to be exactly the same as the previous one. Thus, the following code works with the pageToken (where no nextCall is being used).
call := service.Events.List(calendarID).SingleEvents(true)
events, err := call.Do()
if err != nil {
return err
}
var allEvents []*calendar.Event
allEvents = append(allEvents, events.Items...)
if events.NextPageToken != "" {
nextPageToken := events.NextPageToken
call := call.PageToken(nextPageToken)
events, err = call.Do()
if err != nil {
return err
}
allEvents = append(allEvents, events.Items...)
}

Should there be a new datastore.Client per HTTP request?

The official Go documentation on the datastore package (client library for the GCP datastore service) has the following code snippet for demonstartion:
type Entity struct {
Value string
}
func main() {
ctx := context.Background()
// Create a datastore client. In a typical application, you would create
// a single client which is reused for every datastore operation.
dsClient, err := datastore.NewClient(ctx, "my-project")
if err != nil {
// Handle error.
}
k := datastore.NameKey("Entity", "stringID", nil)
e := new(Entity)
if err := dsClient.Get(ctx, k, e); err != nil {
// Handle error.
}
old := e.Value
e.Value = "Hello World!"
if _, err := dsClient.Put(ctx, k, e); err != nil {
// Handle error.
}
fmt.Printf("Updated value from %q to %q\n", old, e.Value)
}
As one can see, it states that the datastore.Client should ideally only be instantiated once in an application. Now given that the datastore.NewClient function requires a context.Context object does it mean that it should get instantiated only once per HTTP request or can it safely be instantiated once globally with a context.Background() object?
Each operation requires a context.Context object again (e.g. dsClient.Get(ctx, k, e)) so is that the point where the HTTP request's context should be used?
I'm new to Go and can't really find any online resources which explain something like this very well with real world examples and actual best practice patterns.
You may use any context.Context for the datastore client creation, it may be context.Background(), that's completely fine. Client creation may be lengthy, it may require connecting to a remote server, authenticating, fetching configuration etc. If your use case has limited time, you may pass a context with timeout to abort the operation. Also if creation takes longer than the time you have, you may use a context with cancel and abort the mission at your will. These are just options which you may or may not use. But the "tools" are given via context.Context.
Later when you use the datastore.Client during serving (HTTP) client requests, then using the request's context is reasonable, so if a request gets cancelled, then so will its context, and so will the datastore operation you issue, rightfully, because if the client cannot see the result, then there's no point completing the query. Terminating the query early you might not end up using certain resources (e.g. datastore reads), and you may lower the server's load (by aborting jobs whose result will not be sent back to the client).

How to fetch body from imap server in Go

I successfully fetched a list of email headers using the sample code from this url: https://godoc.org/code.google.com/p/go-imap/go1/imap#example-Client . However, I still haven't been able to fetch the body of the emails. Can anyone show some working sample code that could fetch the body of the emails from a imap server in Golang?
I figured out how to get the body text now.
cmd, _ = c.UIDFetch(set, "RFC822.HEADER", "RFC822.TEXT")
// Process responses while the command is running
fmt.Println("\nMost recent messages:")
for cmd.InProgress() {
// Wait for the next response (no timeout)
c.Recv(-1)
// Process command data
for _, rsp = range cmd.Data {
header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])
uid := imap.AsNumber((rsp.MessageInfo().Attrs["UID"]))
body := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.TEXT"])
if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
fmt.Println("|--", msg.Header.Get("Subject"))
fmt.Println("UID: ", uid)
fmt.Println(string(body))
}
}
cmd.Data = nil
c.Data = nil
}
The example code you've linked to demonstrates the use of the IMAP FETCH command to fetch the RFC822.HEADER message data item for a message. The RFC contains a list of standard data items you can fetch from a message.
If you want the entire mime formatted message (both headers and body), then requesting BODY should do. You can get the headers and message body separately by requesting BODY[HEADER] and BODY[TEXT] respectively. Modifying the sample program to use one of these data items should get the data you are after.

Resources