github.com/simpleiot/simpleiot@v0.18.3/client/file.go (about)

     1  package client
     2  
     3  import (
     4  	"crypto/md5"
     5  	"fmt"
     6  	"log"
     7  
     8  	"encoding/base64"
     9  
    10  	"github.com/nats-io/nats.go"
    11  	"github.com/simpleiot/simpleiot/data"
    12  )
    13  
    14  // File represents a file that a user uploads or is present in some location
    15  type File struct {
    16  	ID          string `node:"id"`
    17  	Parent      string `node:"parent"`
    18  	Description string `point:"description"`
    19  	Name        string `point:"name"`
    20  	Data        string `point:"data"`
    21  	Size        string `point:"size"`
    22  	Binary      bool   `point:"binary"`
    23  	Hash        string `point:"hash"`
    24  }
    25  
    26  // GetContents reads the file contents and does any decoding necessary if it is a binary file
    27  func (f *File) GetContents() ([]byte, error) {
    28  	var ret []byte
    29  	var err error
    30  
    31  	if f.Binary {
    32  		ret, err = base64.StdEncoding.DecodeString(f.Data)
    33  	} else {
    34  		ret = []byte(f.Data)
    35  	}
    36  
    37  	return ret, err
    38  }
    39  
    40  // FileClient is used to manage files
    41  type FileClient struct {
    42  	nc            *nats.Conn
    43  	config        File
    44  	stop          chan struct{}
    45  	newPoints     chan NewPoints
    46  	newEdgePoints chan NewPoints
    47  }
    48  
    49  // NewFileClient ...
    50  func NewFileClient(nc *nats.Conn, config File) Client {
    51  	return &FileClient{
    52  		nc:            nc,
    53  		config:        config,
    54  		stop:          make(chan struct{}),
    55  		newPoints:     make(chan NewPoints),
    56  		newEdgePoints: make(chan NewPoints),
    57  	}
    58  }
    59  
    60  // Run the main logic for the file client
    61  func (f *FileClient) Run() error {
    62  
    63  exitFileClient:
    64  
    65  	for {
    66  		select {
    67  		case <-f.stop:
    68  			break exitFileClient
    69  
    70  		case points := <-f.newPoints:
    71  			// Update local configuration
    72  			err := data.MergePoints(points.ID, points.Points, &f.config)
    73  			if err != nil {
    74  				return fmt.Errorf("merging points: %w", err)
    75  			}
    76  
    77  			for _, p := range points.Points {
    78  				if p.Type == data.PointTypeData {
    79  					// update md5 hash
    80  					var fileData []byte
    81  
    82  					fileData, err := f.config.GetContents()
    83  					if err != nil {
    84  						log.Println("Error decoding file contents: ", err)
    85  						break
    86  					}
    87  
    88  					hash := md5.Sum(fileData)
    89  					hashS := fmt.Sprintf("%x", hash)
    90  
    91  					pts := data.Points{
    92  						{Type: data.PointTypeHash, Text: hashS},
    93  						{Type: data.PointTypeSize, Value: float64(len(fileData))},
    94  					}
    95  
    96  					e := SendNodePoints(f.nc, f.config.ID, pts, true)
    97  					if e != nil {
    98  						log.Println("File: error sending hash point: ", err)
    99  					}
   100  				}
   101  			}
   102  		}
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // Stop stops the File Client
   109  func (f *FileClient) Stop(error) {
   110  	close(f.stop)
   111  }
   112  
   113  // Points is called when the client's node points are updated
   114  func (f *FileClient) Points(nodeID string, points []data.Point) {
   115  	f.newPoints <- NewPoints{
   116  		ID:     nodeID,
   117  		Points: points,
   118  	}
   119  }
   120  
   121  // EdgePoints is called when the client's node edge points are updated
   122  func (f *FileClient) EdgePoints(
   123  	_ string, _ string, _ []data.Point,
   124  ) {
   125  	// Do nothing
   126  }