Giter VIP home page Giter VIP logo

deno-grpc's Introduction

/x/grpc_basic

โš ๏ธ You probably should wait for more mature and standard aligned implementation beacuse:

  1. This lib doesn't use Deno's 1.9 HTTP/2 native bindings, but relies on JS implementation roughly ported from node-http2
  2. I'm not an expert in gRPC or HTTP/2, I just moved HTTP/2 frames around until it worked
  3. It was never meant for production use, only for fun and some integration tests and scripts
  4. I have no plans on implementing full gRPC spec

goals - keep it simple

  • load proto files
  • server unary calls
  • client unary calls
  • multiplex calls
  • server server streams
  • client server streams
  • auto reconnects (without retries)
  • deadlines/cancellation with AbortController/AbortSignal
  • call metadata
  • logging interface

non goals - gRPC bloat

  • no TLS
  • no client streams
  • no bidirectional streams
  • no client side load balancing

hello world

greeter.proto

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc ShoutHello (HelloRequest) returns (stream HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

greeter.d.ts

Service typings are not essential, but it's nice to have them

$ deno run --allow-read https://deno.land/x/[email protected]/gen/dts.ts ./greeter.proto > ./greeter.d.ts
export interface Greeter {
  SayHello(request: HelloRequest): Promise<HelloReply>;
  ShoutHello(request: HelloRequest): AsyncGenerator<HelloReply>;
}

export interface HelloRequest {
  name?: string;
}

export interface HelloReply {
  message?: string;
}

server.ts

import { GrpcServer } from "https://deno.land/x/[email protected]/server.ts";
import { Greeter } from "./greeter.d.ts";

const port = 50051;
const server = new GrpcServer();

const protoPath = new URL("./greeter.proto", import.meta.url);
const protoFile = await Deno.readTextFile(protoPath);

server.addService<Greeter>(protoFile, {
  
  async SayHello({ name }) {
    const message = `hello ${name || "stranger"}`;
    return { message };
  },

  async *ShoutHello({ name }) {
    for (const n of [0, 1, 2]) {
      const message = `hello ${name || "stranger"} #${n}`;
      yield { message };
    }
  }
});

console.log(`gonna listen on ${port} port`);
for await (const conn of Deno.listen({ port })) {
  server.handle(conn);
}

client.ts

import { getClient } from "https://deno.land/x/[email protected]/client.ts";
import { Greeter } from "./greeter.d.ts";

const protoPath = new URL("./greeter.proto", import.meta.url);
const protoFile = await Deno.readTextFile(protoPath);

const client = getClient<Greeter>({
  port: 50051,
  root: protoFile,
  serviceName: "Greeter",
});

/* unary calls */
console.log(await client.SayHello({ name: "unary #1" }));
console.log(await client.SayHello({ name: "unary #2" }));

/* server stream */
for await (const reply of client.ShoutHello({ name: "streamed" })) {
  console.log(reply);
}

client.close();

deno-grpc's People

Contributors

mattn avatar prohazko2 avatar rnbguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

deno-grpc's Issues

conn is null

Hi, I'm trying to use this on Windows. client.ts on README.md works good with SayHello but ShoutHello does not.

HelloReply { message: "hello unary #1" }
HelloReply { message: "hello unary #2" }
HelloReply { message: "hello streamed #0" }
HelloReply { message: "hello streamed #1" }
HelloReply { message: "hello streamed #2" }
errrrrrr TypeError: Cannot read properties of null (reading 'write')
    at GrpcClientImpl.sendFrame (https://deno.land/x/[email protected]/client.ts:189:25)
    at GrpcClientImpl.flush (https://deno.land/x/[email protected]/client.ts:172:18)
{ type: "WINDOW_UPDATE", flags: {}, stream: 0, window_size: 72 }
errrrrrr TypeError: Cannot read properties of null (reading 'write')
    at GrpcClientImpl.sendFrame (https://deno.land/x/[email protected]/client.ts:189:25)
    at GrpcClientImpl.flush (https://deno.land/x/[email protected]/client.ts:172:18)
{ type: "WINDOW_UPDATE", flags: {}, stream: 0, window_size: 72 }

Handle imports in protofile

syntax = "proto3";
package etcdserverpb;

import "gogoproto/gogo.proto";
import "etcd/api/mvccpb/kv.proto";
import "etcd/api/authpb/auth.proto";

// for grpc-gateway
import "google/api/annotations.proto";

Server does not work well when multiple parallel calls by client

With change client.ts as shown below and run,
I get an error about once every two times in my environment.

import { getClient } from "https://deno.land/x/[email protected]/client.ts";
import { Greeter } from "./greeter.d.ts";

const protoPath = new URL("./greeter.proto", import.meta.url);
const protoFile = await Deno.readTextFile(protoPath);

const client = getClient<Greeter>({
  port: 50051,
  root: protoFile,
  serviceName: "Greeter",
});

/* unary calls */
await Promise.all([
  client.SayHello({ name: "unary #1" }),
  client.SayHello({ name: "unary #2" }),
]);

client.close();

Error message is

error: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'slice')
      pair = entry.slice();
                   ^
    at HeaderSetDecompressor._execute (https://deno.land/x/[email protected]/http2/hpack.ts:293:20)
    at _execute.next (<anonymous>)
    at Decompressor.decompress (https://deno.land/x/[email protected]/http2/hpack.ts:1377:25)
    at GrpcClientImpl.readFrames (https://deno.land/x/[email protected]/client.ts:240:31)
    at eventLoopTick (ext:core/01_core.js:183:11)

RangeError: index out of range

after n bytes transmited

const client = getClient<Greeter>({
  port: 15070,
  root: protoFile,
  serviceName: "Greeter",
});

for (;;) {
  const name = Math.random().toString(36).repeat(100);
  console.log(await client.SayHello({ name }));
}

figure out how to send http2 trailers

client call - current

[0] Received server headers:
		:status: 200
		content-type: application/grpc+proto
		date: Fri, 16 Apr 2021 00:07:42 GMT
		content-length: 15

[0] receive HTTP/2 data frame of length 15
[0] parsed message of length 15
[0] filterReceivedMessage of length 15
[0] pushing to reader message of length 10
[0] HTTP/2 stream closed with code 0
[0] ended with status: code=13 details="Received RST_STREAM with code 0"

client call - desired

[0] Received server headers:
		:status: 200
		grpc-accept-encoding: identity
		grpc-encoding: identity
		content-type: application/grpc+proto
		date: Fri, 16 Apr 2021 00:09:59 GMT

[0] receive HTTP/2 data frame of length 15
[0] parsed message of length 15
[0] filterReceivedMessage of length 15
[0] pushing to reader message of length 10
[0] Received server trailers:
		grpc-status: 0
		grpc-message: OK

[0] received status code 0 from server
[0] received status details string "OK" from server
[0] ended with status: code=0 details="OK"
[0] close http2 stream with code 0

Wrong d.ts generation

Hi, i have next proto file:

syntax = "proto3";

package some.service.proto;

service Offer {
  rpc Calculate (Request) returns (Response);
}

message Request {
  message Item {
    int32 id = 1;
  }
  repeated Item items = 1;
}

message Response {
  message Collection {
    message Item {
      string name = 1;
    }

    string name = 1;
    repeated Item items = 2;
  }

  repeated Collection collections = 1;
}

after run deno run --allow-read https://deno.land/x/[email protected]/gen/dts.ts ./index.proto > ./generated/index.d.ts i have next d.ts file:

/* this code was generated by automated tool, 
   should not edit by hand */

export interface Offer {
  Calculate(request: Request): Promise<Response>;
}

export interface Request {
  items??: Item[];
}

export interface Item {
  id?: number;
}

export interface Response {
  collections??: Collection[];
}

export interface Collection {
  name?: string;
  items??: Item[];
}

export interface Item {
  name?: string;
}

There are some syntax error (double question marks) and double export of different interfaces with same name.

What am I doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.