client.mx raw

   1  package iskra
   2  
   3  import (
   4  	"fmt"
   5  	"net"
   6  )
   7  
   8  // Client is a synchronous iskra-server client.
   9  type Client struct {
  10  	conn net.Conn
  11  }
  12  
  13  // Dial connects to an iskra-server at addr (e.g. "localhost:4847" or "/run/iskra.sock").
  14  func Dial(addr string) (*Client, error) {
  15  	network := "tcp"
  16  	if len(addr) > 0 && addr[0] == '/' {
  17  		network = "unix"
  18  	}
  19  	conn, err := net.Dial(network, addr)
  20  	if err != nil {
  21  		return nil, err
  22  	}
  23  	return &Client{conn: conn}, nil
  24  }
  25  
  26  func (c *Client) Close() error {
  27  	return c.conn.Close()
  28  }
  29  
  30  func (c *Client) call(req []byte) ([]byte, error) {
  31  	if err := WriteFrame(c.conn, req); err != nil {
  32  		return nil, fmt.Errorf("write: %w", err)
  33  	}
  34  	resp, err := ReadFrame(c.conn)
  35  	if err != nil {
  36  		return nil, fmt.Errorf("read: %w", err)
  37  	}
  38  	if len(resp) == 0 {
  39  		return nil, fmt.Errorf("empty response")
  40  	}
  41  	if resp[0] == StatusError {
  42  		if len(resp) > 1 {
  43  			return nil, fmt.Errorf("server: %s", string(resp[1:]))
  44  		}
  45  		return nil, fmt.Errorf("server error")
  46  	}
  47  	return resp, nil
  48  }
  49  
  50  func (c *Client) ClientBigramWeight(domain uint8, coord uint64, prev, next string) (uint32, error) {
  51  	resp, err := c.call(EncodeBigramWeightReq(domain, coord, prev, next))
  52  	if err != nil {
  53  		return 0, err
  54  	}
  55  	if len(resp) < 5 {
  56  		return 0, fmt.Errorf("short response")
  57  	}
  58  	v, _ := DecodeUint32(resp, 1)
  59  	return v, nil
  60  }
  61  
  62  func (c *Client) ClientBigramWeightRelaxed(domain uint8, coord uint64, prev, next string) (uint32, uint64, error) {
  63  	resp, err := c.call(EncodeBigramWeightRelaxedReq(domain, coord, prev, next))
  64  	if err != nil {
  65  		return 0, 0, err
  66  	}
  67  	if len(resp) < 13 {
  68  		return 0, 0, fmt.Errorf("short response")
  69  	}
  70  	w, _ := DecodeUint32(resp, 1)
  71  	co, _ := DecodeUint64(resp, 5)
  72  	return w, co, nil
  73  }
  74  
  75  func (c *Client) ClientIngestBigram(domain uint8, coord uint64, prev, next string) (uint32, error) {
  76  	resp, err := c.call(EncodeIngestBigramReq(domain, coord, prev, next))
  77  	if err != nil {
  78  		return 0, err
  79  	}
  80  	if len(resp) < 5 {
  81  		return 0, fmt.Errorf("short response")
  82  	}
  83  	v, _ := DecodeUint32(resp, 1)
  84  	return v, nil
  85  }
  86  
  87  func (c *Client) ClientIngestText(domain uint8, coord uint64, tokens []string) error {
  88  	_, err := c.call(EncodeIngestTextReq(domain, coord, tokens))
  89  	return err
  90  }
  91  
  92  func (c *Client) ClientWalkStep(domain uint8, coord uint64, word string, maxCandidates int32) ([]WalkCandidate, error) {
  93  	resp, err := c.call(EncodeWalkStepReq(domain, coord, word, uint16(maxCandidates)))
  94  	if err != nil {
  95  		return nil, err
  96  	}
  97  	if len(resp) < 3 {
  98  		return nil, fmt.Errorf("short response")
  99  	}
 100  	count := int32(uint16(resp[1]) | uint16(resp[2])<<8)
 101  	var candidates []WalkCandidate
 102  	off := 3
 103  	for i := 0; i < count; i++ {
 104  		if off >= len(resp) {
 105  			break
 106  		}
 107  		var cand WalkCandidate
 108  		cand.State.Domain = resp[off]
 109  		off++
 110  		cand.State.Coord, _ = DecodeUint64(resp, off)
 111  		off += 8
 112  		var n int32
 113  		cand.State.Word, n = DecodeString(resp, off)
 114  		off += n
 115  		cand.State.Score, _ = DecodeUint32(resp, off)
 116  		off += 4
 117  		if off < len(resp) {
 118  			cand.State.Depth = resp[off]
 119  			off++
 120  		}
 121  		cand.Weight, _ = DecodeUint32(resp, off)
 122  		off += 4
 123  		candidates = append(candidates, cand)
 124  	}
 125  	return candidates, nil
 126  }
 127  
 128  func (c *Client) ClientTranslate(srcDomain, dstDomain uint8, coord uint64, word string) (string, error) {
 129  	resp, err := c.call(EncodeTranslateReq(srcDomain, dstDomain, coord, word))
 130  	if err != nil {
 131  		return "", err
 132  	}
 133  	if resp[0] == StatusNotFound {
 134  		return "", nil
 135  	}
 136  	s, _ := DecodeString(resp, 1)
 137  	return s, nil
 138  }
 139  
 140  func (c *Client) ClientBeamRun(domain uint8, coord uint64, word string, width, maxSteps int32, kind WalkKind) (WalkState, error) {
 141  	resp, err := c.call(EncodeBeamRunReq(domain, coord, word, uint16(width), uint16(maxSteps), kind))
 142  	if err != nil {
 143  		return WalkState{}, err
 144  	}
 145  	if len(resp) < 15 {
 146  		return WalkState{}, fmt.Errorf("short response")
 147  	}
 148  	var s WalkState
 149  	s.Domain = resp[1]
 150  	s.Depth = resp[2]
 151  	s.Coord, _ = DecodeUint64(resp, 3)
 152  	s.Score, _ = DecodeUint32(resp, 11)
 153  	s.Word, _ = DecodeString(resp, 15)
 154  	return s, nil
 155  }
 156  
 157  func (c *Client) ClientFlush() error {
 158  	_, err := c.call(EncodeFlushReq())
 159  	return err
 160  }
 161