开发一款属于自己的Node游戏服务框架之核心库实现(2)

160 阅读2分钟

前言

上篇文章讲解了项目搭建以及脚手架Cli的搭建和简单的测试,由于目前设计的框架分为socket服务和Rpc服务两部分,那么本篇文章将主要实现创建grpc服务部分

项目环境

  • 系统:windows10
  • Node:v16.14.2
  • pnpm:8.2.0

项目开源地址github.com/whwanyt/pin…

创建

由于要实现socket.io和grpc两个服务并对外保持一直的调用方式,所以将socket.io适配从core包中抽出,在packages目录下新建platform-grpc和platform-socket.io两个包,并进行初始化

安装

实现grpc服务,我们主要是基于@grpc/grpc-js@grpc/proto-loader这两个库来实现

pnpm i @grpc/grpc-js@grpc/proto-loader

platform-socket.io 实现

import { createServer } from "http";
import { Server, ServerOptions as SocketServerOptions } from "socket.io";

export class SocketServer {
  
  private server: Server | undefined;

  create(options: SocketServerOptions) {
    const httpServer = createServer();
    this.server = new Server(httpServer, options as SocketServerOptions);
    return this;
  }

  listen(port: number) {
    this.server!.listen(port);
  }
}

platform-grpc 实现

import {
  Server,
  ServerCredentials,
  loadPackageDefinition,
  UntypedServiceImplementation,
} from "@grpc/grpc-js";
import protoLoader from "@grpc/proto-loader";

export class GrpcServer {

  private server: Server | undefined;
  
  create() {
    this.server = new Server();
    return this;
  }

  listen(host: string) {
    this.server!.bindAsync(host, ServerCredentials.createInsecure(), () => {
      this.server!.start();
    });
  }
}

以上便是对grpc和socket.io的简单库实现,在之后gprc还需要实现client相关,此处先实现服务侧

Core修改

@pinecone/platform-socket.io@pinecone/platform-grpc两个包导入到core项目中并修改初始化方法

import { SocketServer } from "@pinecone/platform-socket.io";
import { GrpcServer } from "@pinecone/platform-grpc";
....
async initialize(options: ServiceOptions) {
    switch (options.transport) {
      case Transport.GRPC:
        return new GrpcServer().create();
      default:
        return new SocketServer().create(options.options);
    }
}

如上便是实现了通过不同的项目启动参数实现不同的服务初始化 修改启动函数

listen(port: number) {
    switch (this.options!.transport) {
      case Transport.GRPC:
        (this.server! as GrpcServer).listen("0.0.0.0:" + port);
        Log.Info(`GrpcServer prot ${port}`, "AppServer");
        break;
      case Transport.SOCKET:
        (this.server! as SocketServer).listen(port);
        Log.Info(`SocketServer prot http://127.0.0.1:${port}`, "AppServer");
        break;
      default:
        Log.Error(`暂不支持该服务类型`, "AppServer");
        break;
    }
}

在上边示例代码中,通过判断是grpc还是socket服务传入host/prot参数

测试

在我们之前创建的example测试项目中先不进行修改直接启动

socket服务启动测试

import { AppFactory, Transport } from "@pinecone/core";
import { AppModule } from "./app";

async function main() {
  const app = await AppFactory.create(AppModule, {
    transport: Transport.GRPC,
    options: {},
  });
  app.listen(3000);
}
main();

image.png

Grpc服务启动测试

import { AppFactory, Transport } from "@pinecone/core";
import { AppModule } from "./app";

async function main() {
  const app = await AppFactory.create(AppModule, {
    transport: Transport.GRPC,
    options: {},
  });
  app.listen(3000);
}
main();

image.png

小结

以上是这个游戏服务框架的Core-Grpc部分的实现,也对项目整体结构进行了进一步优化,下一篇将主要讲解实现一个日志库来实现更优化的日志输出和存储

后记

希望大佬们提出宝贵意见,谢谢👏