kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/storage/stream/stream.go (about) 1 /* 2 * Copyright 2014 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package stream provides utility functions to consume Entry streams. 18 package stream // import "kythe.io/kythe/go/storage/stream" 19 20 import ( 21 "encoding/json" 22 "fmt" 23 "io" 24 25 "kythe.io/kythe/go/platform/delimited" 26 "kythe.io/kythe/go/util/log" 27 "kythe.io/kythe/go/util/schema/facts" 28 29 "google.golang.org/protobuf/encoding/protojson" 30 "google.golang.org/protobuf/proto" 31 32 cpb "kythe.io/kythe/proto/common_go_proto" 33 spb "kythe.io/kythe/proto/storage_go_proto" 34 ) 35 36 // EntryReader functions read a stream of entries, passing each to a handler 37 // function. 38 type EntryReader func(func(*spb.Entry) error) error 39 40 // ReadEntries reads a stream of Entry protobufs from r. 41 func ReadEntries(r io.Reader) <-chan *spb.Entry { 42 ch := make(chan *spb.Entry) 43 go func() { 44 defer close(ch) 45 if err := NewReader(r)(func(e *spb.Entry) error { 46 ch <- e 47 return nil 48 }); err != nil { 49 log.Fatal(err) 50 } 51 }() 52 return ch 53 } 54 55 // NewReader reads a stream of Entry protobufs from r. 56 func NewReader(r io.Reader) EntryReader { 57 return func(f func(*spb.Entry) error) error { 58 rd := delimited.NewReader(r) 59 for { 60 var entry spb.Entry 61 if err := rd.NextProto(&entry); err == io.EOF { 62 return nil 63 } else if err != nil { 64 return fmt.Errorf("error decoding Entry: %v", err) 65 } 66 if err := f((*spb.Entry)(&entry)); err != nil { 67 return err 68 } 69 } 70 } 71 } 72 73 // ReadJSONEntries reads a JSON stream of Entry protobufs from r. 74 func ReadJSONEntries(r io.Reader) <-chan *spb.Entry { 75 ch := make(chan *spb.Entry) 76 go func() { 77 defer close(ch) 78 if err := NewJSONReader(r)(func(e *spb.Entry) error { 79 ch <- e 80 return nil 81 }); err != nil { 82 log.Fatal(err) 83 } 84 }() 85 return ch 86 } 87 88 // StructuredEntry has custom marshaling behavior to handle structured FactValues 89 type StructuredEntry spb.Entry 90 91 // Reset calls the implementation for Entry 92 func (r *StructuredEntry) Reset() { 93 (*spb.Entry)(r).Reset() 94 } 95 96 // String calls the implementation for Entry 97 func (r *StructuredEntry) String() string { 98 return (*spb.Entry)(r).String() 99 } 100 101 // ProtoMessage calls the implementation for Entry 102 func (r *StructuredEntry) ProtoMessage() { 103 (*spb.Entry)(r).ProtoMessage() 104 } 105 106 // NewStructuredJSONReader reads a JSON stream of StructuredEntry protobufs from r. 107 func NewStructuredJSONReader(r io.Reader) EntryReader { 108 return func(f func(*spb.Entry) error) error { 109 de := json.NewDecoder(r) 110 for { 111 var entry StructuredEntry 112 if err := de.Decode(&entry); err == io.EOF { 113 return nil 114 } else if err != nil { 115 return fmt.Errorf("error decoding JSON Entry: %v", err) 116 } 117 if err := f((*spb.Entry)(&entry)); err != nil { 118 return err 119 } 120 } 121 } 122 } 123 124 // NewJSONReader reads a JSON stream of Entry protobufs from r. 125 func NewJSONReader(r io.Reader) EntryReader { 126 return func(f func(*spb.Entry) error) error { 127 de := json.NewDecoder(r) 128 for { 129 var raw json.RawMessage 130 if err := de.Decode(&raw); err == io.EOF { 131 return nil 132 } else if err != nil { 133 return fmt.Errorf("error decoding JSON Entry: %w", err) 134 } 135 var entry spb.Entry 136 if err := protojson.Unmarshal(raw, &entry); err != nil { 137 return fmt.Errorf("error decoding JSON Entry: %w", err) 138 } 139 if err := f(&entry); err != nil { 140 return err 141 } 142 } 143 } 144 } 145 146 var marshaler = protojson.MarshalOptions{UseProtoNames: true} 147 148 // richJSONEntry delays the unmarshaling of the fact_value field 149 type richJSONEntry struct { 150 Source json.RawMessage `json:"source,omitempty"` 151 Target json.RawMessage `json:"target,omitempty"` 152 EdgeKind string `json:"edge_kind,omitempty"` 153 FactName string `json:"fact_name,omitempty"` 154 FactValue json.RawMessage `json:"fact_value,omitempty"` 155 } 156 157 // StructuredFactValueJSON creates a json object from e.FactValue 158 func StructuredFactValueJSON(e *spb.Entry) (json.RawMessage, error) { 159 if e.FactName == facts.Code { 160 var ms cpb.MarkedSource 161 if err := proto.Unmarshal(e.FactValue, &ms); err != nil { 162 return nil, err 163 } 164 rec, err := marshaler.Marshal(&ms) 165 if err != nil { 166 return nil, err 167 } 168 return rec, nil 169 } 170 return json.Marshal(e.FactValue) 171 } 172 173 // Structured creates an entry that serializes factValue to a full value 174 func Structured(e *spb.Entry) *StructuredEntry { 175 return (*StructuredEntry)(e) 176 } 177 178 // UnmarshalJSON unmarshals r including an object representation of FactValue when appropriate 179 func (r *StructuredEntry) UnmarshalJSON(data []byte) error { 180 var jsonEntry richJSONEntry 181 if err := json.Unmarshal(data, &jsonEntry); err != nil { 182 return err 183 } 184 if jsonEntry.FactName == facts.Code { 185 var ms cpb.MarkedSource 186 if err := protojson.Unmarshal(jsonEntry.FactValue, &ms); err != nil { 187 return err 188 } 189 pb, err := proto.Marshal(&ms) 190 if err != nil { 191 return err 192 } 193 r.FactValue = pb 194 } else if err := json.Unmarshal(jsonEntry.FactValue, &r.FactValue); err != nil { 195 return err 196 } 197 198 r.EdgeKind = jsonEntry.EdgeKind 199 r.FactName = jsonEntry.FactName 200 201 var err error 202 if r.Source, err = unmarshalVName(jsonEntry.Source); err != nil { 203 return err 204 } else if r.Target, err = unmarshalVName(jsonEntry.Target); err != nil { 205 return err 206 } 207 208 return nil 209 } 210 211 func marshalVName(v *spb.VName) (json.RawMessage, error) { 212 if v == nil { 213 return nil, nil 214 } 215 return protojson.Marshal(v) 216 } 217 218 func unmarshalVName(msg json.RawMessage) (*spb.VName, error) { 219 if len(msg) == 0 { 220 return nil, nil 221 } 222 var v spb.VName 223 return &v, protojson.Unmarshal(msg, &v) 224 } 225 226 // MarshalJSON marshals r including an object representation of FactValue when appropriate 227 func (r *StructuredEntry) MarshalJSON() ([]byte, error) { 228 jsonEntry := richJSONEntry{ 229 EdgeKind: r.EdgeKind, 230 FactName: r.FactName, 231 } 232 var err error 233 if jsonEntry.Source, err = marshalVName(r.Source); err != nil { 234 return nil, err 235 } else if jsonEntry.Target, err = marshalVName(r.Target); err != nil { 236 return nil, err 237 } else if jsonEntry.FactValue, err = StructuredFactValueJSON((*spb.Entry)(r)); err != nil { 238 return nil, err 239 } 240 241 return json.Marshal(jsonEntry) 242 }