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