Skip to content
This repository has been archived by the owner on Aug 29, 2019. It is now read-only.

Commit

Permalink
New BotApi
Browse files Browse the repository at this point in the history
  • Loading branch information
neonxp committed Aug 13, 2019
1 parent f9744b8 commit 9efc5ff
Show file tree
Hide file tree
Showing 19 changed files with 953 additions and 504 deletions.
103 changes: 45 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,72 @@
# ICQ Bot API
# ICQ Bot Api Go

## Installation
[![Sourcegraph](https://sourcegraph.com/github.com/go-icq/icq/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/go-icq/icq?badge)
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/go-icq/icq)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-icq/icq?style=flat-square)](https://goreportcard.com/report/github.com/go-icq/icq)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/go-icq/icq/master/LICENSE)

Go get: `go get gopkg.in/icq.v2`
Основана на новом Bot Api (https://icq.com/botapi/)

Go mod / Go dep: `import "gopkg.in/icq.v2"`
Реализованы все методы и соответствуют документации.


## Working

Methods:

* SendMessage
* UploadFile
* FetchEvents

Webhooks workds but not recommends

## Example
## Пример

```go
package main

import (
"context"
"fmt"
"log"
"os"
"os/signal"
"time"

"gopkg.in/icq.v2"
"github.com/go-icq/icq"
)

func main() {
// New API object
b := icq.NewAPI(os.Getenv("ICQ_TOKEN"))
// Инициализация
b := icq.NewApi(os.Getenv("ICQ_TOKEN"), icq.ICQ) // or icq.Agent

ctx, cancel := context.WithCancel(context.Background())
// Получение информации о боте
log.Println(b.Self.Get())

ch := make(chan interface{}) // Events channel
osSignal := make(chan os.Signal, 1)
signal.Notify(osSignal, os.Interrupt)
signal.Notify(osSignal, os.Kill)
// Отправка сообщения
resultSend, err := b.Messages.SendText("429950", "Привет!", nil, "", "")
if err != nil {
log.Fatal(err)
}

go b.FetchEvents(ctx, ch) // Events fetch loop
// Отправка файла
resultFile, err := b.Messages.SendFile("429950", "./example/example.jpg", "коржик", []string{resultSend.MsgID}, "", "")
if err != nil {
log.Fatal(err)
}

for {
select {
case e := <-ch:
handleEvent(b, e)
case <-osSignal:
cancel()
break
}
// Отправка существующего файла по ID
_, err = b.Messages.SendExistsFile("429950", resultFile.FileID, "Существующий файл", nil, "", "")
if err != nil {
log.Fatal(err)
}
}

func handleEvent(b *icq.API, event interface{}) {
switch event.(type) {
case *icq.IMEvent:
message := event.(*icq.IMEvent)
if err := handleMessage(b, message); err != nil {
b.SendMessage(icq.Message{
To: message.Data.Source.AimID,
Text: "Message process fail",
})
}
default:
log.Printf("%#v", event)
// Редактирование сообщения
_, err = b.Messages.EditText("429950", "Новый текст", resultSend.MsgID)
if err != nil {
log.Fatal(err)
}
}

func handleMessage(b *icq.API, message *icq.IMEvent) error {
cmd, ok := icq.ParseCommand(message)
if !ok {
return nil
// Будем слушать эвенты 5 минут. При закрытии контекста перестает работать цикл получения событий. В реальном мире контекст надо будет закрывать по сигналу ОС
ctx, _ := context.WithTimeout(context.Background(), 5*time.Minute)
for ev := range b.Events.Get(ctx) {
switch ev := ev.(type) {
case *icq.EventDataMessage:
b.Messages.SendText(ev.Payload.Chat.ChatID, "Echo: "+ev.Payload.Text, []string{ev.Payload.MsgID}, "", "")
default:
log.Println(ev)
}
}
_, err := b.SendMessage(icq.Message{
To: cmd.From,
Text: fmt.Sprintf("Command: %s, Arguments: %v", cmd.Command, cmd.Arguments),
})
return err
}
```

## Автор

Александр NeonXP Кирюхин <[email protected]>
52 changes: 0 additions & 52 deletions api.go

This file was deleted.

68 changes: 68 additions & 0 deletions chats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package icq

import (
"encoding/json"
"net/http"
"net/url"
)

type chats struct {
client *client
}

func newChats(client *client) *chats {
return &chats{client: client}
}

func (s *chats) SendActions(chatID string, actions []ChatAction) (bool, error) {
acts := []string{}
for _, act := range actions {
acts = append(acts, string(act))
}
resp, err := s.client.request(
http.MethodGet,
"/chats/sendActions",
url.Values{
"chatId": []string{chatID},
"actions": acts,
},
nil,
)
if err != nil {
return false, err
}
result := new(OK)
return result.OK, json.NewDecoder(resp).Decode(result)
}

func (s *chats) GetInfo(chatID string) (*Chat, error) {
resp, err := s.client.request(
http.MethodGet,
"/chats/getInfo",
url.Values{
"chatId": []string{chatID},
},
nil,
)
if err != nil {
return nil, err
}
result := new(Chat)
return result, json.NewDecoder(resp).Decode(result)
}

func (s *chats) GetAdmins(chatID string) (*Admins, error) {
resp, err := s.client.request(
http.MethodGet,
"/chats/getAdmins",
url.Values{
"chatId": []string{chatID},
},
nil,
)
if err != nil {
return nil, err
}
result := new(Admins)
return result, json.NewDecoder(resp).Decode(result)
}
75 changes: 75 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package icq

import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"path"
"time"
)

type ApiType int

const (
ICQ ApiType = iota
Agent
)

var servers = map[ApiType]string{
ICQ: "https://api.icq.net/bot/v1/",
Agent: "https://agent.mail.ru/bot/v1/",
}

type client struct {
token string
apiType ApiType
client http.Client
}

func newClient(token string, apiType ApiType) *client {
return &client{token: token, apiType: apiType, client: http.Client{Timeout: 30 * time.Second}}
}

func (c *client) request(method string, methodPath string, query url.Values, body *bytes.Buffer) (io.Reader, error) {
return c.requestWithContentType(method, methodPath, query, body, "")
}

func (c *client) requestWithContentType(method string, methodPath string, query url.Values, body *bytes.Buffer, contentType string) (io.Reader, error) {
query.Set("token", c.token)
u, err := url.Parse(servers[c.apiType])
if err != nil {
return nil, err
}
u.Path = path.Join(u.Path, methodPath)
u.RawQuery = query.Encode()

req, err := http.NewRequest(method, u.String(), nil)
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
if body != nil {
rc := ioutil.NopCloser(body)
req.Body = rc
}

if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
errObj := new(Error)
err = json.NewDecoder(resp.Body).Decode(errObj)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("ok=%v message=%s", errObj.OK, errObj.Description)
}
return resp.Body, err
}
Loading

0 comments on commit 9efc5ff

Please sign in to comment.