Commit d6cc1904 authored by Dmitry Mozzherin's avatar Dmitry Mozzherin
Browse files

Fix #64, fix #65 gRPC improvements

Add method that allows to send an array of names to gRPC. The array
is cleaned up and processed in several go-routines, then assembled
in the same order as intput array.

Move from serving JSON strings y gRPC to real objects. It probably
makes sense to use these gRPC objects internally when gnparser is
used as Go library.
parent b0d2ca9d
Pipeline #78346891 passed with stages
in 7 minutes and 13 seconds
......@@ -2,6 +2,13 @@
## Unreleased
- Add [#65]: gRPC is able to return a protobuf object now instead of JSON
string (only for ParseArray function so far). The same protobuf object is now
also used by gnparser.ParseToObject function.
- Add [#64]: gRPC method ParseArray that cleans and parses an input from an
array of names instead of a stream.
- Add [#63]: abbreviation for `form` or `forma` is now `f.` instead of `fm.`.
## [v0.8.0]
- Add [#51]: strings like `Aus (Bus)` are parsed differently for ICN and ICZN
......@@ -89,6 +96,12 @@ This document follows [changelog guidelines]
[v0.6.0]: https://gitlab.com/gogna/gnparser/compare/v0.5.1...v0.6.0
[v0.5.1]: https://gitlab.com/gogna/gnparser/tree/v0.5.1
[#65]: https://gitlab.com/gogna/gnparser/issues/65
[#64]: https://gitlab.com/gogna/gnparser/issues/64
[#63]: https://gitlab.com/gogna/gnparser/issues/63
[#62]: https://gitlab.com/gogna/gnparser/issues/62
[#61]: https://gitlab.com/gogna/gnparser/issues/61
[#60]: https://gitlab.com/gogna/gnparser/issues/60
[#59]: https://gitlab.com/gogna/gnparser/issues/59
[#58]: https://gitlab.com/gogna/gnparser/issues/58
[#57]: https://gitlab.com/gogna/gnparser/issues/57
......
......@@ -44,17 +44,17 @@ asset:
cd fs; \
$(FLAGS_SHARED) go run -tags=dev assets_gen.go
build: version peg grpc asset
build: version peg pb asset
cd gnparser; \
$(GOCLEAN); \
$(FLAGS_SHARED) $(GOBUILD)
install: version peg grpc asset
install: version peg pb asset
cd gnparser; \
$(GOCLEAN); \
$(FLAGS_SHARED) $(GOINSTALL)
release: version peg grpc asset dockerhub
release: version peg pb asset dockerhub
cd gnparser; \
$(GOCLEAN); \
$(FLAGS_LINUX) $(GOBUILD); \
......@@ -67,9 +67,9 @@ release: version peg grpc asset dockerhub
zip -9 /tmp/gnparser-$(VER)-win-64.zip gnparser.exe; \
$(GOCLEAN);
.PHONY:grpc
grpc:
cd grpc; \
.PHONY:pb
pb:
cd pb; \
protoc -I . ./gnparser.proto --go_out=plugins=grpc:.;
docker: build
......
......@@ -15,14 +15,13 @@ parsed into human readable information as follows:
This parser, written in Go, is the 3rd iteration of the project. The first,
[biodiversity] had been written in Ruby, the second, [also
gnparser][gnparser-scala], had been written in Scala. This project learned
from previous ones, and, when it matures, it is going to be the a
substitution for other two, and will be the only one that is maintained
further. All three projects were developed as a part of [Global Names
Architecture Project][gna].
from the previous ones, and is now a substitution for the other two. It will be
the only one that is maintained further. All three projects were developed as
a part of [Global Names Architecture Project][gna].
Try as a command tool under Windows, Mac or Linux by downloading the [latest
release][releases], uncompressing it, and copying `gnparser` binary somewhere
in your PATH.
To use `gnparser` as a command line tool under Windows, Mac or Linux,
download the [latest release][releases], uncompress it, and copy `gnparser`
binary somewhere in your PATH.
```bash
wget https://www.dropbox.com/s/blvmejmp4378cao/gnparser-v0.5.1-linux.tar.gz
......@@ -67,7 +66,7 @@ gnparser -h
## Introduction
Global Names Parser or ``gnparser`` is a program written in Go for breaking up
scientific names into their different elements. It uses [peg] -- a Parsing
scientific names into their elements. It uses [peg] -- a Parsing
Expression Grammar (PEG) tool.
Many other parsing algorithms for scientific names use regular expressions.
......@@ -353,7 +352,7 @@ ruby] as well as [gRPC documentation].
### Usage as a REST API Interface
Use web-server REST API as a slower, but more wide-spread alternative to
Use web-server REST API as a slower, but a more wide-spread alternative to
gRPC server. Web-based user interface and API are invoked by ``--web-port`` or
``-w`` flag. To start web server on ``http://0.0.0.0:9000``
......@@ -429,18 +428,20 @@ func main() {
}
```
To avoid parsin of JSON gnparser we provide `gnp.ParseToObject` function
To avoid JSON format we provide `gnp.ParseToObject` function.
Use [gnparser.proto] file as a reference of the available object fields.
```
```go
gnp := NewGNparser()
o := gnp.ParseToObject("Homo sapiens")
fmt.Println(o.Canonical)
switch d := o.Details[0].(type) {
case *grammar.SpeciesOutput:
fmt.Println.(d.Genus)
fmt.Println.(d.SpecEpithet)
case *grammar.UninomialOutput:
fmt.Println(d.Uninomial)
fmt.Println(o.Canonical.Simple)
switch d := o.Details.(type) {
case *pb.Parsed_Species:
fmt.Println(d.Species.Genus)
case *pb.Parsed_Uninomial:
fmt.Println(d.Uninomial.Value)
...
}
```
......@@ -499,4 +500,5 @@ Released under [MIT license]
[MIT license]: https://gitlab.com/gogna/gnparser/raw/master/LICENSE
[parser-web]: https://parser.globalnames.org
[IRMNG]: http://www.irmng.org
[CONTRIBUTING]: https://gitlab.com/gogna/gnparser/blob/master/CONTRIBUTING.md
\ No newline at end of file
[CONTRIBUTING]: https://gitlab.com/gogna/gnparser/blob/master/CONTRIBUTING.md
[gnparser.proto]: https://gitlab.com/gogna/gnparser/blob/master/pb/gnparser.proto
\ No newline at end of file
......@@ -2,6 +2,8 @@ package gnparser
import (
"sync"
"gitlab.com/gogna/gnparser/pb"
)
// ParseResult structure contains parsing output and/or error generated
......@@ -36,3 +38,25 @@ func (gnp *GNparser) parserWorker(i int, in <-chan string, out chan<- *ParseResu
out <- &ParseResult{Output: res, Error: nil}
}
}
// ParseStreamToObjects function takes input/output channels to do concurrent
// parsing to object jobs. Output is pushed as ParseObjectResult objects.
func (gnp *GNparser) ParseStreamToObjects(in <-chan string,
out chan<- *pb.Parsed, opts ...Option) {
var wg sync.WaitGroup
wg.Add(gnp.workersNum)
for i := 0; i < gnp.workersNum; i++ {
go gnp.parserObjectWorker(i, in, out, &wg, opts...)
}
wg.Wait()
close(out)
}
func (gnp *GNparser) parserObjectWorker(i int, in <-chan string,
out chan<- *pb.Parsed, wg *sync.WaitGroup, opts ...Option) {
gnp1 := NewGNparser(opts...)
defer wg.Done()
for s := range in {
out <- gnp1.ParseToObject(s)
}
}
......@@ -6,6 +6,7 @@ import (
"runtime"
"strings"
"gitlab.com/gogna/gnparser/pb"
"gitlab.com/gogna/gnparser/preprocess"
"gitlab.com/gogna/gnparser/grammar"
......@@ -134,9 +135,9 @@ func (gnp *GNparser) ParseAndFormat(s string) (string, error) {
// ParseToObject function parses input and
// returns result as output.
func (gnp *GNparser) ParseToObject(s string) *output.Output {
func (gnp *GNparser) ParseToObject(s string) *pb.Parsed {
gnp.Parse(s)
return output.NewOutput(gnp.parser.SN)
return pb.ToPB(output.NewOutput(gnp.parser.SN))
}
// ToPrettyJSON function creates pretty JSON output out of parsed results.
......
......@@ -31,8 +31,8 @@ import (
"github.com/spf13/cobra"
"gitlab.com/gogna/gnparser"
"gitlab.com/gogna/gnparser/grpc"
"gitlab.com/gogna/gnparser/preprocess"
"gitlab.com/gogna/gnparser/rpc"
"gitlab.com/gogna/gnparser/web"
)
......@@ -55,7 +55,8 @@ gnparser names.txt [flags] > parsed_names.txt
To clean names from html tags and entities
gnparser names.txt -c > cleanded_names.txt
To start gRPC parsing service on port 3355 with 10 concurrent jobs:
To start gRPC parsing service on port 3355 with a limit
of 10 concurrent jobs per request:
gnparser -j 10 -g 3355
To start web service on port 8080 with 5 concurrent jobs:
......@@ -74,8 +75,8 @@ gnparser -j 5 -g 8080
if grpcPort != 0 {
fmt.Println("Running gnparser as gRPC service:")
fmt.Printf("port: %d\n", grpcPort)
fmt.Printf("jobs: %d\n\n", wn)
grpc.Run(grpcPort, wn)
fmt.Printf("Max jobs per request: %d\n\n", wn)
rpc.Run(grpcPort, wn)
os.Exit(0)
}
......@@ -316,7 +317,7 @@ func cleanupData(data string, wc int) {
func cleanupFile(f io.Reader, wn int) {
in := make(chan string)
out := make(chan string)
out := make(chan *preprocess.CleanupResult)
var wg sync.WaitGroup
wg.Add(1)
......@@ -336,9 +337,9 @@ func cleanupFile(f io.Reader, wn int) {
wg.Wait()
}
func processCleanup(out <-chan string, wg *sync.WaitGroup) {
func processCleanup(out <-chan *preprocess.CleanupResult, wg *sync.WaitGroup) {
defer wg.Done()
for r := range out {
fmt.Println(r)
fmt.Printf("%s|%s", r.Input, r.Output)
}
}
......@@ -7,7 +7,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
"gitlab.com/gogna/gnparser/grammar"
"gitlab.com/gogna/gnparser/pb"
"gitlab.com/gogna/gnparser/preprocess"
)
......@@ -32,12 +32,32 @@ var _ = Describe("GNparser", func() {
gnp := NewGNparser()
o := gnp.ParseToObject("Homo sapiens")
Expect(o.Parsed).To(Equal(true))
Expect(o.CanonicalName.Simple).To(Equal("Homo sapiens"))
switch d := o.Details[0].(type) {
case *grammar.SpeciesOutput:
Expect(d.Genus.Value).To(Equal("Homo"))
Expect(o.Canonical.Simple).To(Equal("Homo sapiens"))
switch d := o.Details.(type) {
case *pb.Parsed_Species:
Expect(d.Species.Genus).To(Equal("Homo"))
default:
Expect(2).To(Equal(1))
Expect(2).To(Equal(3))
}
})
It("parses hybrid formula", func() {
gnp := NewGNparser()
o := gnp.ParseToObject("Stanhopea tigrina Bateman ex Lindl. x S. ecornuta Lem.")
Expect(o.Parsed).To(Equal(true))
Expect(o.Cardinality).To(Equal(int32(0)))
Expect(pb.NameType_name[int32(o.NameType)]).To(Equal("HYBRID_FORMULA"))
Expect(o.Canonical.Full).To(Equal("Stanhopea tigrina × Stanhopea ecornuta"))
Expect(o.Details).To(BeNil())
det := o.DetailsHybridFormula
Expect(len(det)).To(Equal(2))
for _, v := range det {
switch d := v.Element.(type) {
case *pb.HybridFormula_Species:
Expect(d.Species.Genus).To(Equal("Stanhopea"))
default:
Expect(2).To(Equal(3))
}
}
})
})
......
......@@ -60,11 +60,11 @@ require (
go4.org v0.0.0-20181109185143-00e24f1b2599 // indirect
golang.org/x/build v0.0.0-20190205194203-d0914bad8ebc // indirect
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2 // indirect
golang.org/x/net v0.0.0-20190311183353-d8887717615a
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1 // indirect
golang.org/x/perf v0.0.0-20190124201629-844a5f5b46f4 // indirect
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2
golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c // indirect
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479 // indirect
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 // indirect
google.golang.org/grpc v1.18.0
honnef.co/go/tools v0.0.0-20190128043916-71123fcbb8fe // indirect
......
......@@ -290,6 +290,8 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnY
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -301,6 +303,7 @@ golang.org/x/perf v0.0.0-20190124201629-844a5f5b46f4/go.mod h1:JLpeXjPJfIyPr5Tlb
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
......@@ -371,6 +374,9 @@ golang.org/x/tools v0.0.0-20190212213038-49fb246514cc h1:HSoopeStM6XQJ4+u4t4lu8k
golang.org/x/tools v0.0.0-20190212213038-49fb246514cc/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c h1:hbqcUGBwEHdDbhy8EluQIkbwTIbOvaYedVBif4f2mFQ=
golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479 h1:lfN2PY/jymfnxkNHlbBF5DwPsUvhqUnrdgfK01iH2s0=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
......
......@@ -6,6 +6,17 @@ import (
"gitlab.com/gogna/gnparser/str"
)
type UninomialOutput struct {
Uninomial *uniDetails `json:"uninomial"`
}
type SpeciesOutput struct {
Genus *genusOutput `json:"genus"`
SpecEpithet *specEpithetOutput `json:"specificEpithet"`
SubGenus *subGenusOutput `json:"infragenericEpithet,omitempty"`
InfraSpecies []*InfraSpEpithetOutput `json:"infraspecificEpithets,omitempty"`
}
type ApproxOutput struct {
Genus *genusOutput `json:"genus"`
SpecEpithet *specEpithetOutput `json:"specificEpithet,omitempty"`
......@@ -13,21 +24,14 @@ type ApproxOutput struct {
Ignored *ignoredOutput `json:"ignored,omitempty"`
}
type ignoredOutput struct {
Value string `json:"value"`
}
type ComparisonOutput struct {
Genus *genusOutput `json:"genus"`
SpecEpithet *specEpithetOutput `json:"specificEpithet"`
Comparison string `json:"annotationIdentification"`
}
type SpeciesOutput struct {
Genus *genusOutput `json:"genus"`
SpecEpithet *specEpithetOutput `json:"specificEpithet"`
SubGenus *subGenusOutput `json:"infragenericEpithet,omitempty"`
InfraSpecies []*infraSpEpithetOutput `json:"infraspecificEpithets,omitempty"`
type ignoredOutput struct {
Value string `json:"value"`
}
type genusOutput struct {
......@@ -39,45 +43,36 @@ type subGenusOutput struct {
}
type specEpithetOutput struct {
Value string `json:"value"`
Authorship *authorshipOutput `json:"authorship,omitempty"`
Authorship *AuthorshipOutput `json:"authorship,omitempty"`
}
type infraSpEpithetOutput struct {
type InfraSpEpithetOutput struct {
Value string `json:"value"`
Rank string `json:"rank,omitempty"`
Authorship *authorshipOutput `json:"authorship,omitempty"`
}
type UninomialOutput struct {
Uninomial *uniDetails `json:"uninomial"`
Authorship *AuthorshipOutput `json:"authorship,omitempty"`
}
type uniDetails struct {
Value string `json:"value"`
Rank string `json:"rank,omitempty"`
Parent string `json:"parent,omitempty"`
Authorship *authorshipOutput `json:"authorship,omitempty"`
Authorship *AuthorshipOutput `json:"authorship,omitempty"`
}
type authorshipOutput struct {
type AuthorshipOutput struct {
Value string `json:"value"`
Original *authGroupOutput `json:"basionymAuthorship,omitempty"`
Combination *authGroupOutput `json:"combinationAuthorship,omitempty"`
Original *AuthGroupOutput `json:"basionymAuthorship,omitempty"`
Combination *AuthGroupOutput `json:"combinationAuthorship,omitempty"`
}
type authGroupOutput struct {
Authors []string `json:"authors"`
Year *yearOutput `json:"year,omitempty"`
ExAuthors *exAuthorsOutput `json:"exAuthors,omitempty"`
EmendAuthors *emendAuthorsOutput `json:"emendAuthors,omitempty"`
}
type exAuthorsOutput struct {
Authors []string `json:"authors"`
Year *yearOutput `json:"year,omitempty"`
type AuthGroupOutput struct {
Authors []string `json:"authors"`
Year *yearOutput `json:"year,omitempty"`
ExAuthors *AuthorsOutput `json:"exAuthors,omitempty"`
EmendAuthors *AuthorsOutput `json:"emendAuthors,omitempty"`
}
type emendAuthorsOutput struct {
type AuthorsOutput struct {
Authors []string `json:"authors"`
Year *yearOutput `json:"year,omitempty"`
}
......@@ -125,8 +120,8 @@ func (sn *ScientificNameNode) Details() []interface{} {
return sn.Name.details()
}
func (sn *ScientificNameNode) LastAuthorship() *authorshipOutput {
var ao *authorshipOutput
func (sn *ScientificNameNode) LastAuthorship() *AuthorshipOutput {
var ao *AuthorshipOutput
if sn.Name == nil {
return ao
}
......@@ -278,7 +273,7 @@ func (nh *namedSpeciesHybridNode) details() []interface{} {
if len(nh.InfraSpecies) == 0 {
return []interface{}{so}
}
infs := make([]*infraSpEpithetOutput, len(nh.InfraSpecies))
infs := make([]*InfraSpEpithetOutput, len(nh.InfraSpecies))
for i, v := range nh.InfraSpecies {
infs[i] = v.details()
}
......@@ -487,7 +482,7 @@ func (sp *speciesNode) details() []interface{} {
if len(sp.InfraSpecies) == 0 {
return []interface{}{&so}
}
infs := make([]*infraSpEpithetOutput, len(sp.InfraSpecies))
infs := make([]*InfraSpEpithetOutput, len(sp.InfraSpecies))
for i, v := range sp.InfraSpecies {
infs[i] = v.details()
}
......@@ -562,8 +557,8 @@ func (inf *infraspEpithetNode) canonical() *Canonical {
return &c
}
func (inf *infraspEpithetNode) details() *infraSpEpithetOutput {
var info infraSpEpithetOutput
func (inf *infraspEpithetNode) details() *InfraSpEpithetOutput {
var info InfraSpEpithetOutput
if inf == nil {
return &info
}
......@@ -571,7 +566,7 @@ func (inf *infraspEpithetNode) details() *infraSpEpithetOutput {
if inf.Rank != nil && inf.Rank.Word != nil {
rank = inf.Rank.Word.NormValue
}
info = infraSpEpithetOutput{
info = InfraSpEpithetOutput{
Value: inf.Word.NormValue,
Rank: rank,
Authorship: inf.Authorship.details(),
......@@ -653,12 +648,12 @@ func (u *uninomialComboNode) details() []interface{} {
return []interface{}{&uo}
}
func (au *authorshipNode) details() *authorshipOutput {
func (au *authorshipNode) details() *AuthorshipOutput {
if au == nil {
var ao *authorshipOutput
var ao *AuthorshipOutput
return ao
}
ao := authorshipOutput{Value: au.value()}
ao := AuthorshipOutput{Value: au.value()}
ao.Original = authGroupDetail(au.OriginalAuthors)
if au.CombinationAuthors != nil {
......@@ -667,13 +662,13 @@ func (au *authorshipNode) details() *authorshipOutput {
return &ao
}
func authGroupDetail(ag *authorsGroupNode) *authGroupOutput {
var ago authGroupOutput
func authGroupDetail(ag *authorsGroupNode) *AuthGroupOutput {
var ago AuthGroupOutput
if ag == nil {
return &ago
}
aus, yr := ag.Team1.details()
ago = authGroupOutput{
ago = AuthGroupOutput{
Authors: aus,
Year: yr,
}
......@@ -683,13 +678,13 @@ func authGroupDetail(ag *authorsGroupNode) *authGroupOutput {
aus, yr = ag.Team2.details()
switch ag.Team2Type.Pos.Type {
case AuthorWordExType:
eao := exAuthorsOutput{
eao := AuthorsOutput{
Authors: aus,
Year: yr,
}
ago.ExAuthors = &eao
case AuthorWordEmendType:
eao := emendAuthorsOutput{
eao := AuthorsOutput{
Authors: aus,
Year: yr,
}
......
syntax = "proto3";
package grpc;
message Version {
string value = 1;
string build_time = 2;
}
message Void {}
message Input {
oneof content {
Format format = 1;
string name = 2;
}
}
message Output {
string value = 2;
string error = 3;
}
enum Format {
Compact = 0;
Pretty = 1;
Simple = 2;
Debug = 3;
}
message Cleaned {
string input = 1;
string output = 2;
}
service GNparser {
rpc Ver(Void) returns(Version) {}
rpc Parse(stream Input) returns(stream Output) {}
rpc ParseInOrder(stream Input) returns(stream Output) {}
rpc Clean(stream Input) returns(stream Cleaned) {}
rpc CleanInOrder(stream Input) returns(stream Cleaned) {}
}
package grpc
import (
"fmt"
"io"
"log"
"net"
"strings"
"sync"
"gitlab.com/gogna/gnparser"
"gitlab.com/gogna/gnparser/dict"
"gitlab.com/gogna/gnparser/output"
"gitlab.com/gogna/gnparser/preprocess"
context "golang.org/x/net/context"
"google.golang.org/grpc"
)
type parseStream interface {
Send(*Output) error
Recv() (*Input, error)
grpc.ServerStream
}
type cleanStream interface {
Send(*Cleaned) error
Recv() (*Input, error)
grpc.ServerStream
}
type gnparserServer struct {
WorkersNum int
}
func (gnparserServer) Ver(ctx context.Context,
v *Void) (*Version, error) {
ver := output.Version
build := output.Build
return &Version{Value: ver, BuildTime: build}, nil
}