Basic IDEC proto implementation in Go

This commit is contained in:
Denis Zheleztsov 2017-02-09 23:17:28 +03:00
parent 44c9c8c4b0
commit 5971ff5530
3 changed files with 274 additions and 0 deletions

35
idec/messages.go Normal file
View File

@ -0,0 +1,35 @@
package idec
import (
"encoding/base64"
"strings"
)
// Message IDEC message structure
type Message struct {
From string `json:"from"`
To string `json:"to"`
Address string `json:"address"`
Echo string `json:"echo"`
Subg string `json:"subg"`
ID string `json:"id"`
Timestamp int `json:"timestamp"`
Body string `json:"body"`
Tags string `json:"tags"`
Repto string `json:"repto"`
}
// PrepareMessageForSend Make base64 encoded message
func PrepareMessageForSend(m Message) string {
var result string
var rawMessage string
if m.Repto != "" {
rawMessage = strings.Join([]string{m.Echo, m.To, m.Subg, "", m.Repto, m.Body}, "\n")
}
rawMessage = strings.Join([]string{m.Echo, m.To, m.Subg, "", m.Body}, "\n")
result = base64.StdEncoding.EncodeToString([]byte(rawMessage))
return result
}

56
idec/parser.go Normal file
View File

@ -0,0 +1,56 @@
package idec
import (
"encoding/base64"
"strconv"
"strings"
)
// ParseMessage ...
func ParseMessage(message string) (Message, error) {
var m Message
plainMessage, err := base64.StdEncoding.DecodeString(message)
if err != nil {
return m, err
}
txtMessage := strings.Split(string(plainMessage), "\n")
var body string
for i := 8; i < len(txtMessage); i++ {
body = strings.Join([]string{body, txtMessage[i]}, "\n")
}
ts, err := strconv.Atoi(txtMessage[2])
if err != nil {
return m, err
}
m.Tags = txtMessage[0]
m.Echo = txtMessage[1]
m.Timestamp = ts
m.From = txtMessage[3]
m.Address = txtMessage[4]
m.To = txtMessage[5]
m.Subg = txtMessage[6]
m.Body = body
return m, err
}
// ParseEchoList parse /list.txt
func ParseEchoList(list string) ([]Echo, error) {
var echoes []Echo
for _, e := range strings.Split(list, "\n") {
desc := strings.Split(e, ":")
if len(desc) <= 1 {
break
}
count, err := strconv.Atoi(desc[1])
if err != nil {
return echoes, err
}
echoes = append(echoes, Echo{desc[0], count, desc[2]})
}
return echoes, nil
}

183
idec/proto.go Normal file
View File

@ -0,0 +1,183 @@
package idec
// Base IDEC protocol implementation
import (
"errors"
"io/ioutil"
"net/http"
"strconv"
"strings"
)
// IDEC Extensions. see: https://ii-net.tk/idec-doc/?p=extensions
const (
listTXT = "list.txt"
blacklistTXT = "blacklist.txt"
features = "x/features"
xcount = "x/c/"
echoSchema = "u/e/"
messageSchema = "u/m/"
)
// Extensions IDEC extensions
type Extensions struct {
ListTXT string `json:"list_txt"`
BlacklistTXT string `json:"backlist_txt"`
Features string `json:"features"`
XCount string `json:"xcount"`
}
// NewExtensions ...
func NewExtensions() Extensions {
e := Extensions{
listTXT,
blacklistTXT,
features,
xcount,
}
return e
}
// FetchConfig node, echo, and other connection settings
type FetchConfig struct {
Node string `json:"node"`
Echoes []string `json:"echo"`
Num int `json:"count"`
Offset int `json:"offset"`
Limit int `json:"limit"`
}
// ID ...
type ID struct {
Echo string `json:"echo"`
MsgID string `json:"msgids"`
}
// GetMessagesIDS get message ids from node
func (f FetchConfig) GetMessagesIDS() ([]ID, error) {
var ids []ID
var getURI string
getEchoes := strings.Join(f.Echoes, "/")
// Make strings
offset := strconv.Itoa(f.Offset)
limit := strconv.Itoa(f.Limit)
getURI = strings.Join([]string{f.Node, echoSchema, getEchoes, "/", offset, ":", limit}, "")
// Get messages ids
response, err := http.Get(getURI)
if err != nil {
return ids, err
}
defer response.Body.Close()
c, err := ioutil.ReadAll(response.Body)
if err != nil {
return ids, err
}
var i ID
var curEcho string
rawIDS := strings.Split(string(c), "\n")
for _, line := range rawIDS {
// Match echoarea
if strings.Contains(line, ".") {
curEcho = line
continue
}
// Match message ID
if !strings.Contains(line, ".") && !strings.Contains(line, ":") && line != "" {
i.Echo = curEcho
i.MsgID = line
ids = append(ids, i)
}
}
return ids, nil
}
// GetRawMessages get messages from node
func (f FetchConfig) GetRawMessages(ids []ID) ([]string, error) {
var messages []string
var messagesIDS []string
for _, id := range ids {
messagesIDS = append(messagesIDS, id.MsgID)
}
getMessages := strings.Join(messagesIDS, "/")
getURI := strings.Join([]string{f.Node, messageSchema, getMessages}, "")
// Get messages ids
response, err := http.Get(getURI)
if err != nil {
return messages, err
}
defer response.Body.Close()
c, err := ioutil.ReadAll(response.Body)
if err != nil {
return messages, err
}
for _, m := range strings.Split(string(c), "\n") {
if len(m) == 0 {
break
}
message := strings.Split(m, ":")
if len(message) > 0 {
messages = append(messages, message[1])
}
}
return messages, err
}
// Echo echo description
type Echo struct {
Name string `json:"name"`
Size int `json:"size"`
Description string `json:"description"`
}
// GetEchoList ...
func (f FetchConfig) GetEchoList() ([]Echo, error) {
var echoes []Echo
// Check node features support
fres, err := http.Get(strings.Join([]string{f.Node, features}, "/"))
if err != nil {
return echoes, err
}
defer fres.Body.Close()
c, err := ioutil.ReadAll(fres.Body)
if err != nil {
return echoes, err
}
if !strings.Contains(string(c), listTXT) {
err = errors.New("Node does not support echoes list")
return echoes, err
}
lres, err := http.Get(strings.Join([]string{f.Node, listTXT}, "/"))
if err != nil {
return echoes, err
}
defer lres.Body.Close()
l, err := ioutil.ReadAll(lres.Body)
if err != nil {
return echoes, err
}
echoes, err = ParseEchoList(string(l))
return echoes, err
}