-
Notifications
You must be signed in to change notification settings - Fork 161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mvp 版本讨论 #322
Comments
辛苦东哥,protobuf这边没有问题; invoker这边比较关心最终生成代码的调用方式,期待 @creasy2010 更新 |
ok,可以以这个例子作为开始 |
@creasy2010 目前生成的代码是什么样子 |
因为protocolbuff 强依赖proto或者proto生成的valid type文件定义,所以IDL生成的代码需要和序列化模块耦合起来 序列化接口设计interface Serialization {
// load 所有的proto文件,获取request类型
loadProto(protoPath: string): void;
// encode 请求数据,后置type参数且是可选,为了将来切换其他协议如不需要type类型,可以不传,我们接口可以不改
encode<T>(data: T, type?: string): Buffer;
// decode 请求数据,后置type参数且是可选,为了将来切换其他协议如不需要type类型,可以不传,我们接口可以不改
decode<T>(data: Buffer, type?: string): T;
} 序列化模块的设计
IDL 代码生成针对Mvp的proto定义,对client stub service代码样例: // define service interface
export interface Mvp {
SayHello(req: HelloRequest): Promise<HelloReply>;
Check(req: HealthCheckRequest): Promise<HealthCheckResponse>;
}
// define enum
enum ServingStatus {
UNKNOWN = 0,
SERVING = 1,
NOT_SERVING = 2,
SERVICE_UNKNOWN = 3, // Used only by the Watch method.
}
// define request && response, 实际代码可以根据不同的namespace生成到不同的目录
export interface HealthCheckResponse {
status: ServingStatus;
}
export interface HealthCheckRequest {
service: string;
}
export interface HelloRequest {
name: string;
}
export interface HelloReply {
message: string;
}
// define service metadata
import ds from 'dubbo-serialization'
// TODO 或者对于ecode和decode的过程,IDL生成代码只返回 {path, data} 由invoke来负责底层的调用
export const Mvp = {
SayHello: {
path: "/helloworld.Mvp/SayHello",
encode(data: HelloRequest) {
return ds.encode(data, ` hellorequest在对象path路径 `)
},
decode(data: Buffer) {
return ds.decode(data, `helloreplay 的path路径 `)
}
},
Check: {
path: "/helloworld.Mvp/Check",
encode(data: HealthCheckRequest) {
return ds.encode(data, ` HealthCheckRequest在对象path路径 `)
},
decode(data: Buffer) {
return ds.decode(data, `helloreplay 的path路径 `)
}
},
};
// server 端
// 生成抽象类
export abstract class AbstractMvp {
path = "/helloworld.Greeter";
methods = {
SayHello: this.SayHello.bind(this),
Check: this.Check.bind(this),
};
abstract SayHello(req: HelloRequest): Promise<HelloReply>;
abstract Check(req: HealthCheckRequest): Promise<HealthCheckResponse>;
}
// 生成实现类
export class MvpService extends AbstractMvp {
SayHello(req: HelloRequest): Promise<HelloReply> {
throw new Error("Method not implemented.");
}
Check(req: HealthCheckRequest): Promise<HealthCheckResponse> {
throw new Error("Method not implemented.");
}
}
|
基于Mvp,实际invoker的调用方式如下: // define DubboClientsTstubService
export interface DubboClientsTstubService {
mvp: IMvp;
}
// index.ts
import DubboClient from './../dubbo'
import stubService from './stubServices'
import {DubboClientsTstubService} from './mvpService'
const dubbo = new DubboClient<DubboClientsTstubService>(stubService) |
client 里的 path 和 methods 的一一对应关系是不是要和 server 这边的逻辑一致? |
经讨论确认,dubbo-server 的抽象类生成形式如下所示: export abstract class AbstractMvp {
metaData:{
'/helloworld.Greeter/SayHello': this.SayHello.bind(this),
'/helloworld.Greeter/Check': this.Check.bind(this)
};
abstract SayHello(req: HelloRequest): Promise<HelloReply>;
abstract Check(req: HealthCheckRequest): Promise<HealthCheckResponse>;
} dubbo-client 模块依此做对应调整。 @hufeng @fengwei5280 |
调整后的 transport mvp pr入口:#325 入口 import { DubboClientTransport } from './client'
import { DubboServerTransport } from './server'
export { DubboClientTransport, DubboServerTransport } client transport 代码 import { debug } from 'debug'
import http2 from 'node:http2'
import { IDubboClientTransport, DubboContext } from './transport'
// init log
const log = debug('dubbo3:transport:client')
export class DubboClientTransport implements IDubboClientTransport {
// transport 实例
private transport: any
private ctx: DubboContext
constructor(opts: DubboContext) {
this.ctx = opts
this.connect()
}
get url() {
return this.ctx.url
}
/**
* 建立连接
*/
connect() {
this.transport = http2.connect(this.url)
this.transport.once('connect', () => {
log('has connected')
})
}
/**
* 发送消息
* @param msg
*/
async send(msg: DubboContext): Promise<void> {
this.transport.request(msg)
}
} server transport 代码: import debug from 'debug'
import EventEmitter from 'node:events'
import http2 from 'node:http2'
import { IDubboServerTransport, DubboContext } from './transport'
// init log
const log = debug('dubbo3:transport:client')
export class DubboServerTransport
extends EventEmitter
implements IDubboServerTransport
{
private ctx: DubboContext
transport: any
constructor(opts: DubboContext) {
super()
this.ctx = opts
this.transport = this.start()
}
get url() {
return this.ctx.url
}
get port() {
return this.ctx.port
}
/**
* 启动服务端 transport
* @returns
*/
start() {
const server = http2.createServer()
server.on('stream', (stream, headers) => {
log(stream)
stream.on('data', (data) => {
log(data)
// TODO:
})
stream.on('end', () => {
log('end...')
// TODO: 通知 client
})
stream.on('error', (error) => {
log(error)
})
})
server.listen(this.port)
return server
}
} tansport.ts 接口定义: export interface DubboContext {
url: string
body?: Object | null
port: number
}
export interface IDubboClientTransport {
send(msg: DubboContext): Promise<any>
}
export interface IDubboServerTransport {
// start(msg: DubboContext): Promise<any>
} 依赖:
|
context的数据和定义 @godkun export default class Context {
path: string
method: string
args: Array<any>
resolve: Fuction
reject: Fuction
// final result
body: any
} |
以此为Mvp目标,大家看看是否有要补充的。
The text was updated successfully, but these errors were encountered: