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  }