github.com/unirita/cuto@v0.9.8-0.20160830082821-aa6652f877b7/realtime/network/network.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/csv"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"strconv"
    12  
    13  	scan "github.com/mattn/go-scan"
    14  
    15  	"github.com/unirita/cuto/flowgen/converter"
    16  )
    17  
    18  // Number of columns
    19  const columns = 14
    20  
    21  // Indexes of columns
    22  const (
    23  	nameIdx = iota
    24  	nodeIdx
    25  	portIdx
    26  	pathIdx
    27  	paramIdx
    28  	envIdx
    29  	workIdx
    30  	wrcIdx
    31  	wptnIdx
    32  	ercIdx
    33  	eptnIdx
    34  	timeoutIdx
    35  	snodeIdx
    36  	sportIdx
    37  )
    38  
    39  var jobex = make([][]string, 0)
    40  
    41  // LoadJobex loads jobex csv which corresponds to name.
    42  // LoadJobex returns empty jobex array if csv is not exists.
    43  func LoadJobex(name string, nwkDir string) error {
    44  	csvPath := searchJobexCsvFile(name, nwkDir)
    45  	if csvPath == "" {
    46  		return nil
    47  	}
    48  
    49  	file, err := os.Open(csvPath)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	defer file.Close()
    54  
    55  	jobex, err = loadJobexFromReader(file)
    56  	return err
    57  }
    58  
    59  func searchJobexCsvFile(name string, nwkDir string) string {
    60  	individualPath := filepath.Join(nwkDir, "realtime", name+".csv")
    61  	defaultPath := filepath.Join(nwkDir, "realtime", "default.csv")
    62  
    63  	if _, err := os.Stat(individualPath); !os.IsNotExist(err) {
    64  		return individualPath
    65  	}
    66  	if _, err := os.Stat(defaultPath); !os.IsNotExist(err) {
    67  		return defaultPath
    68  	}
    69  
    70  	return ""
    71  }
    72  
    73  // loadJobexFromReader reads reader as csv format, and create jobex data array.
    74  func loadJobexFromReader(reader io.Reader) ([][]string, error) {
    75  	r := csv.NewReader(reader)
    76  	result := make([][]string, 0)
    77  	isTitleRow := true
    78  	for {
    79  		record, err := r.Read()
    80  		if err == io.EOF {
    81  			break
    82  		} else if err != nil {
    83  			return nil, err
    84  		}
    85  		if !isTitleRow {
    86  			result = append(result, record)
    87  		}
    88  		isTitleRow = false
    89  	}
    90  	if len(result) > 0 && len(result[0]) != columns {
    91  		return nil, fmt.Errorf("Number of jobex csv columns[%d] must be %d.", len(result[0]), columns)
    92  	}
    93  
    94  	return result, nil
    95  }
    96  
    97  func getJobexRecordByName(jobname string) []string {
    98  	for _, record := range jobex {
    99  		if record[nameIdx] == jobname {
   100  			return record
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  type Network struct {
   107  	Flow string `json:"flow"`
   108  	Jobs []Job  `json:"jobs"`
   109  }
   110  
   111  // Parse parses str as json format, and create Network object.
   112  func Parse(reader io.Reader) (*Network, error) {
   113  	decorder := json.NewDecoder(reader)
   114  
   115  	network := new(Network)
   116  	if err := decorder.Decode(network); err != nil {
   117  		return nil, err
   118  	}
   119  	network.complementJobs()
   120  
   121  	if err := network.DetectError(); err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	return network, nil
   126  }
   127  
   128  func (n *Network) complementJobs() {
   129  	for _, record := range jobex {
   130  		isExists := false
   131  		for _, job := range n.Jobs {
   132  			if record[nameIdx] == job.Name {
   133  				isExists = true
   134  				break
   135  			}
   136  		}
   137  
   138  		if !isExists {
   139  			newJob := Job{Name: record[nameIdx]}
   140  			newJob.importJobex()
   141  			n.Jobs = append(n.Jobs, newJob)
   142  		}
   143  	}
   144  }
   145  
   146  // DetectError detects error in Network object, and return it.
   147  // If there is no error, DetectError returns nil.
   148  func (n *Network) DetectError() error {
   149  	for _, job := range n.Jobs {
   150  		if job.Name == "" {
   151  			return errors.New("Anonymous job detected.")
   152  		}
   153  	}
   154  	return nil
   155  }
   156  
   157  func (n *Network) Export(name, nwkDir string) error {
   158  	flowPath := filepath.Join(nwkDir, name+".bpmn")
   159  	jobexPath := filepath.Join(nwkDir, name+".csv")
   160  
   161  	flowHead, err := converter.ParseString(n.Flow)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	definition := converter.GenerateDefinitions(flowHead)
   166  	if err := converter.ExportFile(flowPath, definition); err != nil {
   167  		return err
   168  	}
   169  
   170  	file, err := os.Create(jobexPath)
   171  	if err != nil {
   172  		return err
   173  	}
   174  	defer file.Close()
   175  	if err := n.exportJob(file); err != nil {
   176  		return nil
   177  	}
   178  
   179  	return nil
   180  }
   181  
   182  func (n *Network) Clean(name, nwkDir string) {
   183  	flowPath := filepath.Join(nwkDir, name+".bpmn")
   184  	jobexPath := filepath.Join(nwkDir, name+".csv")
   185  	os.Remove(flowPath)
   186  	os.Remove(jobexPath)
   187  }
   188  
   189  func (n *Network) exportJob(writer io.Writer) error {
   190  	w := csv.NewWriter(writer)
   191  	// Add title record.
   192  	if err := w.Write(make([]string, columns)); err != nil {
   193  		return err
   194  	}
   195  
   196  	for _, job := range n.Jobs {
   197  		record := make([]string, columns)
   198  		record[nameIdx] = job.Name
   199  		record[nodeIdx] = job.Node
   200  		record[portIdx] = strconv.Itoa(job.Port)
   201  		record[pathIdx] = job.Path
   202  		record[paramIdx] = job.Param
   203  		record[envIdx] = job.Env
   204  		record[workIdx] = job.Work
   205  		record[wrcIdx] = strconv.Itoa(job.WRC)
   206  		record[wptnIdx] = job.WPtn
   207  		record[ercIdx] = strconv.Itoa(job.ERC)
   208  		record[eptnIdx] = job.EPtn
   209  		record[timeoutIdx] = strconv.Itoa(job.Timeout)
   210  		record[snodeIdx] = job.SNode
   211  		record[sportIdx] = strconv.Itoa(job.SPort)
   212  		if err := w.Write(record); err != nil {
   213  			return err
   214  		}
   215  	}
   216  	w.Flush()
   217  	return nil
   218  }
   219  
   220  type Job struct {
   221  	Name    string
   222  	Node    string
   223  	Port    int
   224  	Path    string
   225  	Param   string
   226  	Env     string
   227  	Work    string
   228  	WRC     int
   229  	WPtn    string
   230  	ERC     int
   231  	EPtn    string
   232  	Timeout int
   233  	SNode   string
   234  	SPort   int
   235  }
   236  
   237  // UnmarshalJSON create job object from data(JSON format).
   238  // Use jobex value loaded by LoadJobex function if the parameter is null.
   239  func (j *Job) UnmarshalJSON(data []byte) error {
   240  	var i interface{}
   241  	if err := json.Unmarshal(data, &i); err != nil {
   242  		return err
   243  	}
   244  	if err := scan.ScanTree(i, "/name", &j.Name); err != nil {
   245  		return err
   246  	}
   247  	j.importJobex()
   248  
   249  	// scan.ScanTree does not change value of 3rd parameter when error occured.
   250  	scan.ScanTree(i, "/node", &j.Node)
   251  	scan.ScanTree(i, "/port", &j.Port)
   252  	scan.ScanTree(i, "/path", &j.Path)
   253  	scan.ScanTree(i, "/param", &j.Param)
   254  	scan.ScanTree(i, "/env", &j.Env)
   255  	scan.ScanTree(i, "/work", &j.Work)
   256  	scan.ScanTree(i, "/wrc", &j.WRC)
   257  	scan.ScanTree(i, "/wptn", &j.WPtn)
   258  	scan.ScanTree(i, "/erc", &j.ERC)
   259  	scan.ScanTree(i, "/eptn", &j.EPtn)
   260  	scan.ScanTree(i, "/timeout", &j.Timeout)
   261  	scan.ScanTree(i, "/snode", &j.SNode)
   262  	scan.ScanTree(i, "/sport", &j.SPort)
   263  
   264  	return nil
   265  }
   266  
   267  func (j *Job) importJobex() {
   268  	for _, record := range jobex {
   269  		if record[nameIdx] == j.Name {
   270  			var err error
   271  			j.Node = record[nodeIdx]
   272  			j.Port, err = strconv.Atoi(record[portIdx])
   273  			if err != nil {
   274  				j.Port = 0
   275  			}
   276  			j.Path = record[pathIdx]
   277  			j.Param = record[paramIdx]
   278  			j.Env = record[envIdx]
   279  			j.Work = record[workIdx]
   280  			j.WRC, err = strconv.Atoi(record[wrcIdx])
   281  			if err != nil {
   282  				j.WRC = 0
   283  			}
   284  			j.WPtn = record[wptnIdx]
   285  			j.ERC, err = strconv.Atoi(record[ercIdx])
   286  			if err != nil {
   287  				j.ERC = 0
   288  			}
   289  			j.EPtn = record[eptnIdx]
   290  			j.Timeout, err = strconv.Atoi(record[timeoutIdx])
   291  			if err != nil {
   292  				j.Timeout = 0
   293  			}
   294  			j.SNode = record[snodeIdx]
   295  			j.SPort, err = strconv.Atoi(record[sportIdx])
   296  			if err != nil {
   297  				j.SPort = 0
   298  			}
   299  		}
   300  	}
   301  }