protocol.mx raw

   1  package main
   2  
   3  // Protocol: pipe-delimited, newline-terminated messages.
   4  // REQ|<seq>|<op>|<arg0>|<arg1>|...
   5  // OK|<seq>|<result>
   6  // ERR|<seq>|<errmsg>
   7  
   8  func tsItoa(n int32) (s string) {
   9  	if n == 0 {
  10  		return "0"
  11  	}
  12  	buf := []byte{:0:20}
  13  	neg := n < 0
  14  	if neg {
  15  		n = -n
  16  	}
  17  	for n > 0 {
  18  		push(buf, byte('0'+n%10))
  19  		n /= 10
  20  	}
  21  	if neg {
  22  		push(buf, '-')
  23  	}
  24  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
  25  		buf[i], buf[j] = buf[j], buf[i]
  26  	}
  27  	return string(buf)
  28  }
  29  
  30  func tsAtoi(s string) (n int32) {
  31  	if len(s) == 0 {
  32  		return 0
  33  	}
  34  	neg := false
  35  	pos := int32(0)
  36  	if s[0] == '-' {
  37  		neg = true
  38  		pos = 1
  39  	} else if s[0] == '+' {
  40  		pos = 1
  41  	}
  42  	for pos < int32(len(s)) {
  43  		c := s[pos]
  44  		if c < '0' || c > '9' {
  45  			break
  46  		}
  47  		n = n*10 + int32(c-'0')
  48  		pos++
  49  	}
  50  	if neg {
  51  		n = -n
  52  	}
  53  	return n
  54  }
  55  
  56  func parseMsg(msg string) (seq int32, op string, args []string) {
  57  	parts := splitMsg(msg)
  58  	if len(parts) < 3 {
  59  		return 0, "", nil
  60  	}
  61  	seq = tsAtoi(parts[1])
  62  	op = parts[2]
  63  	if len(parts) > 3 {
  64  		args = parts[3:]
  65  	}
  66  	return seq, op, args
  67  }
  68  
  69  func formatOK(seq int32, result string) (s string) {
  70  	return "OK|" | tsItoa(seq) | "|" | result | "\n"
  71  }
  72  
  73  func formatERR(seq int32, errmsg string) (s string) {
  74  	return "ERR|" | tsItoa(seq) | "|" | errmsg | "\n"
  75  }
  76  
  77  func parseOK(line string) (result string) {
  78  	parts := splitMsg(line)
  79  	if len(parts) >= 3 {
  80  		return parts[2]
  81  	}
  82  	return ""
  83  }
  84  
  85  func parseOKMulti(line string) (results []string) {
  86  	return splitMsg(line)
  87  }
  88  
  89  func parseERR(line string) (errmsg string) {
  90  	parts := splitMsg(line)
  91  	if len(parts) >= 3 {
  92  		return parts[2]
  93  	}
  94  	return ""
  95  }
  96  
  97  func splitMsg(d string) (parts []string) {
  98  	if len(d) == 0 {
  99  		return nil
 100  	}
 101  	n := int32(1)
 102  	for i := int32(0); i < int32(len(d)); i++ {
 103  		if d[i] == '|' {
 104  			n++
 105  		}
 106  	}
 107  	parts = []string{:0:n}
 108  	start := int32(0)
 109  	for i := int32(0); i <= int32(len(d)); i++ {
 110  		isDelim := false
 111  		if i < int32(len(d)) {
 112  			isDelim = d[i] == '|' || d[i] == '\n'
 113  		}
 114  		if i == int32(len(d)) || isDelim {
 115  			push(parts, string(d[start:i]))
 116  			start = i + 1
 117  			if i < int32(len(d)) && d[i] == '\n' {
 118  				break
 119  			}
 120  		}
 121  	}
 122  	return parts
 123  }
 124