firehol/netdata

View on GitHub
src/go/plugin/go.d/agent/functions/function.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package functions

import (
    "bytes"
    "context"
    "encoding/csv"
    "fmt"
    "strconv"
    "strings"
    "time"
)

type Function struct {
    key         string
    UID         string
    Timeout     time.Duration
    Name        string
    Args        []string
    Payload     []byte
    Permissions string
    Source      string
    ContentType string
}

func (f *Function) String() string {
    return fmt.Sprintf("key: '%s', uid: '%s', timeout: '%s', function: '%s', args: '%v', permissions: '%s', source: '%s',  contentType: '%s', payload: '%s'",
        f.key, f.UID, f.Timeout, f.Name, f.Args, f.Permissions, f.Source, f.ContentType, string(f.Payload))
}

func parseFunction(s string) (*Function, error) {
    r := csv.NewReader(strings.NewReader(s))
    r.Comma = ' '

    parts, err := r.Read()
    if err != nil {
        return nil, err
    }

    // FUNCTION UID Timeout "Name ...Parameters" 0xPermissions "SourceType" [ContentType]
    if n := len(parts); n != 6 && n != 7 {
        return nil, fmt.Errorf("unexpected number of words: want 6 or 7, got %d (%v)", n, parts)
    }

    timeout, err := strconv.ParseInt(parts[2], 10, 64)
    if err != nil {
        return nil, err
    }

    cmd := strings.Split(parts[3], " ")

    fn := &Function{
        key:         parts[0],
        UID:         parts[1],
        Timeout:     time.Duration(timeout) * time.Second,
        Name:        cmd[0],
        Args:        cmd[1:],
        Permissions: parts[4],
        Source:      parts[5],
    }

    if len(parts) == 7 {
        fn.ContentType = parts[6]
    }

    return fn, nil
}

func parseFunctionWithPayload(ctx context.Context, s string, in input) (*Function, error) {
    fn, err := parseFunction(s)
    if err != nil {
        return nil, err
    }

    var buf bytes.Buffer

    for {
        select {
        case <-ctx.Done():
            return nil, nil
        case line, ok := <-in.lines():
            if !ok {
                return nil, nil
            }
            if line == "FUNCTION_PAYLOAD_END" {
                fn.Payload = append(fn.Payload, buf.Bytes()...)
                return fn, nil
            }
            if buf.Len() > 0 {
                buf.WriteString("\n")
            }
            buf.WriteString(line)
        }
    }
}