tcp协议
parent
e75813a8cd
commit
d44078eca5
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,205 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: msgtype.proto
|
||||
#pragma warning disable 1591, 0612, 3021
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
namespace Message {
|
||||
|
||||
/// <summary>Holder for reflection information generated from msgtype.proto</summary>
|
||||
public static partial class MsgtypeReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for msgtype.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static MsgtypeReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"Cg1tc2d0eXBlLnByb3RvEgdtZXNzYWdlIgcKBUVycm9yKvEBCghNU0dfVFlQ",
|
||||
"RRIKCgZfRVJST1IQABIKCgZfTG9naW4QARIQCgxfTG9naW5SZXN1bHQQAhIO",
|
||||
"CgpfUGxheVN0YXJ0EAMSFAoQX1BsYXlTdGFydFJlc3VsdBAEEgwKCF9QbGF5",
|
||||
"RW5kEAUSEgoOX1BsYXlFbmRSZXN1bHQQBhILCgdfUmVwb3J0EAcSEQoNX1Jl",
|
||||
"cG9ydFJlc3VsdBAIEgwKCF9HZXRSYW5rEAkSEgoOX0dldFJhbmtSZXN1bHQQ",
|
||||
"ChIWChJfTm90aWZ5TmV3QXVkaWVuY2UQCxIZChVfTm90aWZ5QXVkaWVuY2VB",
|
||||
"Y3Rpb24QDCpzCgpFUlJPUl9DT0RFEgsKB1NVQ0NFU1MQABIICgRGQUlMEAES",
|
||||
"EQoNSU5WQUxJRF9BUFBJRBACEhEKDUlOVkFMSURfVE9LRU4QAxITCg9HQU1F",
|
||||
"X0lTX1JVTk5JTkcQBBITCg9HQU1FX0lTX1NUT1BQRUQQBUIFWgNwYi9iBnBy",
|
||||
"b3RvMw=="));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Message.MSG_TYPE), typeof(global::Message.ERROR_CODE), }, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::Message.Error), global::Message.Error.Parser, null, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Enums
|
||||
public enum MSG_TYPE {
|
||||
/// <summary>
|
||||
/// Error
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_ERROR")] Error = 0,
|
||||
/// <summary>
|
||||
/// Login
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_Login")] Login = 1,
|
||||
/// <summary>
|
||||
/// LoginResult
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_LoginResult")] LoginResult = 2,
|
||||
/// <summary>
|
||||
/// PlayStart
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_PlayStart")] PlayStart = 3,
|
||||
/// <summary>
|
||||
/// PlayStartResult
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_PlayStartResult")] PlayStartResult = 4,
|
||||
/// <summary>
|
||||
/// PlayEnd
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_PlayEnd")] PlayEnd = 5,
|
||||
/// <summary>
|
||||
/// PlayEndResult
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_PlayEndResult")] PlayEndResult = 6,
|
||||
/// <summary>
|
||||
/// Report
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_Report")] Report = 7,
|
||||
/// <summary>
|
||||
/// ReportResult
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_ReportResult")] ReportResult = 8,
|
||||
/// <summary>
|
||||
/// GetRank
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_GetRank")] GetRank = 9,
|
||||
/// <summary>
|
||||
/// GetRankResult
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_GetRankResult")] GetRankResult = 10,
|
||||
/// <summary>
|
||||
/// NotifyNewAudience
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_NotifyNewAudience")] NotifyNewAudience = 11,
|
||||
/// <summary>
|
||||
/// NotifyAudienceAction
|
||||
/// </summary>
|
||||
[pbr::OriginalName("_NotifyAudienceAction")] NotifyAudienceAction = 12,
|
||||
}
|
||||
|
||||
public enum ERROR_CODE {
|
||||
[pbr::OriginalName("SUCCESS")] Success = 0,
|
||||
[pbr::OriginalName("FAIL")] Fail = 1,
|
||||
[pbr::OriginalName("INVALID_APPID")] InvalidAppid = 2,
|
||||
[pbr::OriginalName("INVALID_TOKEN")] InvalidToken = 3,
|
||||
[pbr::OriginalName("GAME_IS_RUNNING")] GameIsRunning = 4,
|
||||
[pbr::OriginalName("GAME_IS_STOPPED")] GameIsStopped = 5,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Messages
|
||||
public sealed partial class Error : pb::IMessage<Error> {
|
||||
private static readonly pb::MessageParser<Error> _parser = new pb::MessageParser<Error>(() => new Error());
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public static pb::MessageParser<Error> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Message.MsgtypeReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public Error() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public Error(Error other) : this() {
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public Error Clone() {
|
||||
return new Error(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as Error);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public bool Equals(Error other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public void MergeFrom(Error other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion Designer generated code
|
||||
@ -0,0 +1,98 @@
|
||||
syntax = "proto3";
|
||||
package message;
|
||||
option go_package = "pb/";
|
||||
|
||||
import "msgtype.proto";
|
||||
|
||||
message Login
|
||||
{
|
||||
string AppId = 1;
|
||||
string Token = 2;
|
||||
}
|
||||
|
||||
message LoginResult
|
||||
{
|
||||
ERROR_CODE Result = 1;
|
||||
string RoomId = 2;
|
||||
string UID = 3;
|
||||
string NickName = 4;
|
||||
}
|
||||
|
||||
message PlayStart
|
||||
{
|
||||
}
|
||||
|
||||
message PlayStartResult
|
||||
{
|
||||
ERROR_CODE Result = 1;
|
||||
}
|
||||
|
||||
message PlayEnd
|
||||
{
|
||||
}
|
||||
|
||||
message PlayEndResult
|
||||
{
|
||||
ERROR_CODE Result = 1;
|
||||
}
|
||||
|
||||
message Report
|
||||
{
|
||||
repeated ReportInfo Info = 1;
|
||||
}
|
||||
|
||||
message ReportResult
|
||||
{
|
||||
ERROR_CODE Result = 1;
|
||||
}
|
||||
|
||||
message GetRank
|
||||
{
|
||||
int32 TopCount = 1;
|
||||
}
|
||||
|
||||
message GetRankResult
|
||||
{
|
||||
ERROR_CODE Result = 1;
|
||||
repeated ReportInfo Info = 2;
|
||||
}
|
||||
|
||||
//新用户推送
|
||||
message NotifyNewAudience
|
||||
{
|
||||
Audience Audience = 1;
|
||||
}
|
||||
//用户行为推送
|
||||
message NotifyAudienceAction
|
||||
{
|
||||
string OpenId = 1;
|
||||
string Content = 2; //评论
|
||||
int32 LikeNum = 3; //点赞数量
|
||||
string GiftId = 4; //礼物ID
|
||||
int32 GiftNum = 5; //礼物数量
|
||||
}
|
||||
|
||||
//============结构============
|
||||
|
||||
//分数信息
|
||||
message ReportInfo
|
||||
{
|
||||
string OpenId = 1;
|
||||
int32 Score = 2;
|
||||
}
|
||||
|
||||
//观众信息
|
||||
message Audience
|
||||
{
|
||||
string OpenId = 1;
|
||||
string NickName = 2;
|
||||
string AvatarUrl = 3;
|
||||
}
|
||||
|
||||
//排名信息
|
||||
message RankInfo
|
||||
{
|
||||
Audience Audience = 1; //观众信息
|
||||
int32 Rank = 2; //排名
|
||||
int32 Score = 3; //用户分数
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
syntax = "proto3";
|
||||
package message;
|
||||
option go_package = "pb/";
|
||||
|
||||
enum MSG_TYPE
|
||||
{
|
||||
_ERROR = 0; //Error
|
||||
_Login = 1; //Login
|
||||
_LoginResult = 2; //LoginResult
|
||||
_PlayStart = 3; //PlayStart
|
||||
_PlayStartResult = 4; //PlayStartResult
|
||||
_PlayEnd = 5; //PlayEnd
|
||||
_PlayEndResult = 6; //PlayEndResult
|
||||
_Report = 7; //Report
|
||||
_ReportResult = 8; //ReportResult
|
||||
_GetRank = 9; //GetRank
|
||||
_GetRankResult = 10; //GetRankResult
|
||||
_NotifyNewAudience = 11; //NotifyNewAudience
|
||||
_NotifyAudienceAction = 12; //NotifyAudienceAction
|
||||
}
|
||||
|
||||
enum ERROR_CODE
|
||||
{
|
||||
SUCCESS = 0;
|
||||
FAIL = 1;
|
||||
INVALID_APPID = 2;
|
||||
INVALID_TOKEN = 3;
|
||||
GAME_IS_RUNNING = 4;
|
||||
GAME_IS_STOPPED = 5;
|
||||
}
|
||||
|
||||
message Error
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
@ echo off
|
||||
cd ./protoc/bin
|
||||
set protoPath="../../"
|
||||
set clientPath="../../Proto"
|
||||
set serverPath="../../../src/app/message"
|
||||
protoc.exe -I=%protoPath% --csharp_out=%clientPath% --go_out=%serverPath% %protoPath%/*.proto
|
||||
clang-format.exe -i -style="{AlignConsecutiveAssignments: true,AlignConsecutiveDeclarations: true,AllowShortFunctionsOnASingleLine: None,BreakBeforeBraces: GNU,ColumnLimit: 0,IndentWidth: 4,Language: Proto}" %protoPath%/*.proto
|
||||
pause
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,158 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/anypb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "AnyProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
// URL that describes the type of the serialized message.
|
||||
//
|
||||
// Protobuf library provides support to pack/unpack Any values in the form
|
||||
// of utility functions or additional generated methods of the Any type.
|
||||
//
|
||||
// Example 1: Pack and unpack a message in C++.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any;
|
||||
// any.PackFrom(foo);
|
||||
// ...
|
||||
// if (any.UnpackTo(&foo)) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Example 2: Pack and unpack a message in Java.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any = Any.pack(foo);
|
||||
// ...
|
||||
// if (any.is(Foo.class)) {
|
||||
// foo = any.unpack(Foo.class);
|
||||
// }
|
||||
//
|
||||
// Example 3: Pack and unpack a message in Python.
|
||||
//
|
||||
// foo = Foo(...)
|
||||
// any = Any()
|
||||
// any.Pack(foo)
|
||||
// ...
|
||||
// if any.Is(Foo.DESCRIPTOR):
|
||||
// any.Unpack(foo)
|
||||
// ...
|
||||
//
|
||||
// Example 4: Pack and unpack a message in Go
|
||||
//
|
||||
// foo := &pb.Foo{...}
|
||||
// any, err := anypb.New(foo)
|
||||
// if err != nil {
|
||||
// ...
|
||||
// }
|
||||
// ...
|
||||
// foo := &pb.Foo{}
|
||||
// if err := any.UnmarshalTo(foo); err != nil {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The pack methods provided by protobuf library will by default use
|
||||
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
// methods only use the fully qualified type name after the last '/'
|
||||
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
// name "y.z".
|
||||
//
|
||||
//
|
||||
// JSON
|
||||
// ====
|
||||
// The JSON representation of an `Any` value uses the regular
|
||||
// representation of the deserialized, embedded message, with an
|
||||
// additional field `@type` which contains the type URL. Example:
|
||||
//
|
||||
// package google.profile;
|
||||
// message Person {
|
||||
// string first_name = 1;
|
||||
// string last_name = 2;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.profile.Person",
|
||||
// "firstName": <string>,
|
||||
// "lastName": <string>
|
||||
// }
|
||||
//
|
||||
// If the embedded message type is well-known and has a custom JSON
|
||||
// representation, that representation will be embedded adding a field
|
||||
// `value` which holds the custom JSON in addition to the `@type`
|
||||
// field. Example (for message [google.protobuf.Duration][]):
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
// "value": "1.212s"
|
||||
// }
|
||||
//
|
||||
message Any {
|
||||
// A URL/resource name that uniquely identifies the type of the serialized
|
||||
// protocol buffer message. This string must contain at least
|
||||
// one "/" character. The last segment of the URL's path must represent
|
||||
// the fully qualified name of the type (as in
|
||||
// `path/google.protobuf.Duration`). The name should be in a canonical form
|
||||
// (e.g., leading "." is not accepted).
|
||||
//
|
||||
// In practice, teams usually precompile into the binary all types that they
|
||||
// expect it to use in the context of Any. However, for URLs which use the
|
||||
// scheme `http`, `https`, or no scheme, one can optionally set up a type
|
||||
// server that maps type URLs to message definitions as follows:
|
||||
//
|
||||
// * If no scheme is provided, `https` is assumed.
|
||||
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
// value in binary format, or produce an error.
|
||||
// * Applications are allowed to cache lookup results based on the
|
||||
// URL, or have them precompiled into a binary to avoid any
|
||||
// lookup. Therefore, binary compatibility needs to be preserved
|
||||
// on changes to types. (Use versioned type names to manage
|
||||
// breaking changes.)
|
||||
//
|
||||
// Note: this functionality is not currently available in the official
|
||||
// protobuf release, and it is not used for type URLs beginning with
|
||||
// type.googleapis.com.
|
||||
//
|
||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
// used with implementation specific semantics.
|
||||
//
|
||||
string type_url = 1;
|
||||
|
||||
// Must be a valid serialized protocol buffer of the above specified type.
|
||||
bytes value = 2;
|
||||
}
|
||||
@ -0,0 +1,208 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
import "google/protobuf/source_context.proto";
|
||||
import "google/protobuf/type.proto";
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "ApiProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option go_package = "google.golang.org/protobuf/types/known/apipb";
|
||||
|
||||
// Api is a light-weight descriptor for an API Interface.
|
||||
//
|
||||
// Interfaces are also described as "protocol buffer services" in some contexts,
|
||||
// such as by the "service" keyword in a .proto file, but they are different
|
||||
// from API Services, which represent a concrete implementation of an interface
|
||||
// as opposed to simply a description of methods and bindings. They are also
|
||||
// sometimes simply referred to as "APIs" in other contexts, such as the name of
|
||||
// this message itself. See https://cloud.google.com/apis/design/glossary for
|
||||
// detailed terminology.
|
||||
message Api {
|
||||
// The fully qualified name of this interface, including package name
|
||||
// followed by the interface's simple name.
|
||||
string name = 1;
|
||||
|
||||
// The methods of this interface, in unspecified order.
|
||||
repeated Method methods = 2;
|
||||
|
||||
// Any metadata attached to the interface.
|
||||
repeated Option options = 3;
|
||||
|
||||
// A version string for this interface. If specified, must have the form
|
||||
// `major-version.minor-version`, as in `1.10`. If the minor version is
|
||||
// omitted, it defaults to zero. If the entire version field is empty, the
|
||||
// major version is derived from the package name, as outlined below. If the
|
||||
// field is not empty, the version in the package name will be verified to be
|
||||
// consistent with what is provided here.
|
||||
//
|
||||
// The versioning schema uses [semantic
|
||||
// versioning](http://semver.org) where the major version number
|
||||
// indicates a breaking change and the minor version an additive,
|
||||
// non-breaking change. Both version numbers are signals to users
|
||||
// what to expect from different versions, and should be carefully
|
||||
// chosen based on the product plan.
|
||||
//
|
||||
// The major version is also reflected in the package name of the
|
||||
// interface, which must end in `v<major-version>`, as in
|
||||
// `google.feature.v1`. For major versions 0 and 1, the suffix can
|
||||
// be omitted. Zero major versions must only be used for
|
||||
// experimental, non-GA interfaces.
|
||||
//
|
||||
//
|
||||
string version = 4;
|
||||
|
||||
// Source context for the protocol buffer service represented by this
|
||||
// message.
|
||||
SourceContext source_context = 5;
|
||||
|
||||
// Included interfaces. See [Mixin][].
|
||||
repeated Mixin mixins = 6;
|
||||
|
||||
// The source syntax of the service.
|
||||
Syntax syntax = 7;
|
||||
}
|
||||
|
||||
// Method represents a method of an API interface.
|
||||
message Method {
|
||||
// The simple name of this method.
|
||||
string name = 1;
|
||||
|
||||
// A URL of the input message type.
|
||||
string request_type_url = 2;
|
||||
|
||||
// If true, the request is streamed.
|
||||
bool request_streaming = 3;
|
||||
|
||||
// The URL of the output message type.
|
||||
string response_type_url = 4;
|
||||
|
||||
// If true, the response is streamed.
|
||||
bool response_streaming = 5;
|
||||
|
||||
// Any metadata attached to the method.
|
||||
repeated Option options = 6;
|
||||
|
||||
// The source syntax of this method.
|
||||
Syntax syntax = 7;
|
||||
}
|
||||
|
||||
// Declares an API Interface to be included in this interface. The including
|
||||
// interface must redeclare all the methods from the included interface, but
|
||||
// documentation and options are inherited as follows:
|
||||
//
|
||||
// - If after comment and whitespace stripping, the documentation
|
||||
// string of the redeclared method is empty, it will be inherited
|
||||
// from the original method.
|
||||
//
|
||||
// - Each annotation belonging to the service config (http,
|
||||
// visibility) which is not set in the redeclared method will be
|
||||
// inherited.
|
||||
//
|
||||
// - If an http annotation is inherited, the path pattern will be
|
||||
// modified as follows. Any version prefix will be replaced by the
|
||||
// version of the including interface plus the [root][] path if
|
||||
// specified.
|
||||
//
|
||||
// Example of a simple mixin:
|
||||
//
|
||||
// package google.acl.v1;
|
||||
// service AccessControl {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v1/{resource=**}:getAcl";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// package google.storage.v2;
|
||||
// service Storage {
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl);
|
||||
//
|
||||
// // Get a data record.
|
||||
// rpc GetData(GetDataRequest) returns (Data) {
|
||||
// option (google.api.http).get = "/v2/{resource=**}";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Example of a mixin configuration:
|
||||
//
|
||||
// apis:
|
||||
// - name: google.storage.v2.Storage
|
||||
// mixins:
|
||||
// - name: google.acl.v1.AccessControl
|
||||
//
|
||||
// The mixin construct implies that all methods in `AccessControl` are
|
||||
// also declared with same name and request/response types in
|
||||
// `Storage`. A documentation generator or annotation processor will
|
||||
// see the effective `Storage.GetAcl` method after inheriting
|
||||
// documentation and annotations as follows:
|
||||
//
|
||||
// service Storage {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v2/{resource=**}:getAcl";
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Note how the version in the path pattern changed from `v1` to `v2`.
|
||||
//
|
||||
// If the `root` field in the mixin is specified, it should be a
|
||||
// relative path under which inherited HTTP paths are placed. Example:
|
||||
//
|
||||
// apis:
|
||||
// - name: google.storage.v2.Storage
|
||||
// mixins:
|
||||
// - name: google.acl.v1.AccessControl
|
||||
// root: acls
|
||||
//
|
||||
// This implies the following inherited HTTP annotation:
|
||||
//
|
||||
// service Storage {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
message Mixin {
|
||||
// The fully qualified name of the interface which is included.
|
||||
string name = 1;
|
||||
|
||||
// If non-empty specifies a path under which inherited HTTP paths
|
||||
// are rooted.
|
||||
string root = 2;
|
||||
}
|
||||
@ -0,0 +1,183 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to
|
||||
// change.
|
||||
//
|
||||
// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is
|
||||
// just a program that reads a CodeGeneratorRequest from stdin and writes a
|
||||
// CodeGeneratorResponse to stdout.
|
||||
//
|
||||
// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead
|
||||
// of dealing with the raw protocol defined here.
|
||||
//
|
||||
// A plugin executable needs only to be placed somewhere in the path. The
|
||||
// plugin should be named "protoc-gen-$NAME", and will then be used when the
|
||||
// flag "--${NAME}_out" is passed to protoc.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package google.protobuf.compiler;
|
||||
option java_package = "com.google.protobuf.compiler";
|
||||
option java_outer_classname = "PluginProtos";
|
||||
|
||||
option go_package = "google.golang.org/protobuf/types/pluginpb";
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
// The version number of protocol compiler.
|
||||
message Version {
|
||||
optional int32 major = 1;
|
||||
optional int32 minor = 2;
|
||||
optional int32 patch = 3;
|
||||
// A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
|
||||
// be empty for mainline stable releases.
|
||||
optional string suffix = 4;
|
||||
}
|
||||
|
||||
// An encoded CodeGeneratorRequest is written to the plugin's stdin.
|
||||
message CodeGeneratorRequest {
|
||||
// The .proto files that were explicitly listed on the command-line. The
|
||||
// code generator should generate code only for these files. Each file's
|
||||
// descriptor will be included in proto_file, below.
|
||||
repeated string file_to_generate = 1;
|
||||
|
||||
// The generator parameter passed on the command-line.
|
||||
optional string parameter = 2;
|
||||
|
||||
// FileDescriptorProtos for all files in files_to_generate and everything
|
||||
// they import. The files will appear in topological order, so each file
|
||||
// appears before any file that imports it.
|
||||
//
|
||||
// protoc guarantees that all proto_files will be written after
|
||||
// the fields above, even though this is not technically guaranteed by the
|
||||
// protobuf wire format. This theoretically could allow a plugin to stream
|
||||
// in the FileDescriptorProtos and handle them one by one rather than read
|
||||
// the entire set into memory at once. However, as of this writing, this
|
||||
// is not similarly optimized on protoc's end -- it will store all fields in
|
||||
// memory at once before sending them to the plugin.
|
||||
//
|
||||
// Type names of fields and extensions in the FileDescriptorProto are always
|
||||
// fully qualified.
|
||||
repeated FileDescriptorProto proto_file = 15;
|
||||
|
||||
// The version number of protocol compiler.
|
||||
optional Version compiler_version = 3;
|
||||
|
||||
}
|
||||
|
||||
// The plugin writes an encoded CodeGeneratorResponse to stdout.
|
||||
message CodeGeneratorResponse {
|
||||
// Error message. If non-empty, code generation failed. The plugin process
|
||||
// should exit with status code zero even if it reports an error in this way.
|
||||
//
|
||||
// This should be used to indicate errors in .proto files which prevent the
|
||||
// code generator from generating correct code. Errors which indicate a
|
||||
// problem in protoc itself -- such as the input CodeGeneratorRequest being
|
||||
// unparseable -- should be reported by writing a message to stderr and
|
||||
// exiting with a non-zero status code.
|
||||
optional string error = 1;
|
||||
|
||||
// A bitmask of supported features that the code generator supports.
|
||||
// This is a bitwise "or" of values from the Feature enum.
|
||||
optional uint64 supported_features = 2;
|
||||
|
||||
// Sync with code_generator.h.
|
||||
enum Feature {
|
||||
FEATURE_NONE = 0;
|
||||
FEATURE_PROTO3_OPTIONAL = 1;
|
||||
}
|
||||
|
||||
// Represents a single generated file.
|
||||
message File {
|
||||
// The file name, relative to the output directory. The name must not
|
||||
// contain "." or ".." components and must be relative, not be absolute (so,
|
||||
// the file cannot lie outside the output directory). "/" must be used as
|
||||
// the path separator, not "\".
|
||||
//
|
||||
// If the name is omitted, the content will be appended to the previous
|
||||
// file. This allows the generator to break large files into small chunks,
|
||||
// and allows the generated text to be streamed back to protoc so that large
|
||||
// files need not reside completely in memory at one time. Note that as of
|
||||
// this writing protoc does not optimize for this -- it will read the entire
|
||||
// CodeGeneratorResponse before writing files to disk.
|
||||
optional string name = 1;
|
||||
|
||||
// If non-empty, indicates that the named file should already exist, and the
|
||||
// content here is to be inserted into that file at a defined insertion
|
||||
// point. This feature allows a code generator to extend the output
|
||||
// produced by another code generator. The original generator may provide
|
||||
// insertion points by placing special annotations in the file that look
|
||||
// like:
|
||||
// @@protoc_insertion_point(NAME)
|
||||
// The annotation can have arbitrary text before and after it on the line,
|
||||
// which allows it to be placed in a comment. NAME should be replaced with
|
||||
// an identifier naming the point -- this is what other generators will use
|
||||
// as the insertion_point. Code inserted at this point will be placed
|
||||
// immediately above the line containing the insertion point (thus multiple
|
||||
// insertions to the same point will come out in the order they were added).
|
||||
// The double-@ is intended to make it unlikely that the generated code
|
||||
// could contain things that look like insertion points by accident.
|
||||
//
|
||||
// For example, the C++ code generator places the following line in the
|
||||
// .pb.h files that it generates:
|
||||
// // @@protoc_insertion_point(namespace_scope)
|
||||
// This line appears within the scope of the file's package namespace, but
|
||||
// outside of any particular class. Another plugin can then specify the
|
||||
// insertion_point "namespace_scope" to generate additional classes or
|
||||
// other declarations that should be placed in this scope.
|
||||
//
|
||||
// Note that if the line containing the insertion point begins with
|
||||
// whitespace, the same whitespace will be added to every line of the
|
||||
// inserted text. This is useful for languages like Python, where
|
||||
// indentation matters. In these languages, the insertion point comment
|
||||
// should be indented the same amount as any inserted code will need to be
|
||||
// in order to work correctly in that context.
|
||||
//
|
||||
// The code generator that generates the initial file and the one which
|
||||
// inserts into it must both run as part of a single invocation of protoc.
|
||||
// Code generators are executed in the order in which they appear on the
|
||||
// command line.
|
||||
//
|
||||
// If |insertion_point| is present, |name| must also be present.
|
||||
optional string insertion_point = 2;
|
||||
|
||||
// The file contents.
|
||||
optional string content = 15;
|
||||
|
||||
// Information describing the file content being inserted. If an insertion
|
||||
// point is used, this information will be appropriately offset and inserted
|
||||
// into the code generation metadata for the generated files.
|
||||
optional GeneratedCodeInfo generated_code_info = 16;
|
||||
}
|
||||
repeated File file = 15;
|
||||
}
|
||||
@ -0,0 +1,911 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// The messages in this file describe the definitions found in .proto files.
|
||||
// A valid .proto file can be translated directly to a FileDescriptorProto
|
||||
// without any other information (e.g. without reading its imports).
|
||||
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/types/descriptorpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DescriptorProtos";
|
||||
option csharp_namespace = "Google.Protobuf.Reflection";
|
||||
option objc_class_prefix = "GPB";
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// descriptor.proto must be optimized for speed because reflection-based
|
||||
// algorithms don't work during bootstrapping.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// The protocol compiler can output a FileDescriptorSet containing the .proto
|
||||
// files it parses.
|
||||
message FileDescriptorSet {
|
||||
repeated FileDescriptorProto file = 1;
|
||||
}
|
||||
|
||||
// Describes a complete .proto file.
|
||||
message FileDescriptorProto {
|
||||
optional string name = 1; // file name, relative to root of source tree
|
||||
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
// Indexes of the public imported files in the dependency list above.
|
||||
repeated int32 public_dependency = 10;
|
||||
// Indexes of the weak imported files in the dependency list.
|
||||
// For Google-internal migration only. Do not use.
|
||||
repeated int32 weak_dependency = 11;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
repeated EnumDescriptorProto enum_type = 5;
|
||||
repeated ServiceDescriptorProto service = 6;
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
|
||||
// This field contains optional information about the original source code.
|
||||
// You may safely remove this entire field without harming runtime
|
||||
// functionality of the descriptors -- the information is needed only by
|
||||
// development tools.
|
||||
optional SourceCodeInfo source_code_info = 9;
|
||||
|
||||
// The syntax of the proto file.
|
||||
// The supported values are "proto2" and "proto3".
|
||||
optional string syntax = 12;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
message DescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated FieldDescriptorProto field = 2;
|
||||
repeated FieldDescriptorProto extension = 6;
|
||||
|
||||
repeated DescriptorProto nested_type = 3;
|
||||
repeated EnumDescriptorProto enum_type = 4;
|
||||
|
||||
message ExtensionRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Exclusive.
|
||||
|
||||
optional ExtensionRangeOptions options = 3;
|
||||
}
|
||||
repeated ExtensionRange extension_range = 5;
|
||||
|
||||
repeated OneofDescriptorProto oneof_decl = 8;
|
||||
|
||||
optional MessageOptions options = 7;
|
||||
|
||||
// Range of reserved tag numbers. Reserved tag numbers may not be used by
|
||||
// fields or extension ranges in the same message. Reserved ranges may
|
||||
// not overlap.
|
||||
message ReservedRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Exclusive.
|
||||
}
|
||||
repeated ReservedRange reserved_range = 9;
|
||||
// Reserved field names, which may not be used by fields in the same message.
|
||||
// A given name may only be reserved once.
|
||||
repeated string reserved_name = 10;
|
||||
}
|
||||
|
||||
message ExtensionRangeOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
// Describes a field within a message.
|
||||
message FieldDescriptorProto {
|
||||
enum Type {
|
||||
// 0 is reserved for errors.
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
|
||||
// negative values are likely.
|
||||
TYPE_INT64 = 3;
|
||||
TYPE_UINT64 = 4;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
|
||||
// negative values are likely.
|
||||
TYPE_INT32 = 5;
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
TYPE_STRING = 9;
|
||||
// Tag-delimited aggregate.
|
||||
// Group type is deprecated and not supported in proto3. However, Proto3
|
||||
// implementations should still be able to parse the group wire format and
|
||||
// treat group fields as unknown fields.
|
||||
TYPE_GROUP = 10;
|
||||
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
||||
|
||||
// New in version 2.
|
||||
TYPE_BYTES = 12;
|
||||
TYPE_UINT32 = 13;
|
||||
TYPE_ENUM = 14;
|
||||
TYPE_SFIXED32 = 15;
|
||||
TYPE_SFIXED64 = 16;
|
||||
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
||||
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
||||
}
|
||||
|
||||
enum Label {
|
||||
// 0 is reserved for errors
|
||||
LABEL_OPTIONAL = 1;
|
||||
LABEL_REQUIRED = 2;
|
||||
LABEL_REPEATED = 3;
|
||||
}
|
||||
|
||||
optional string name = 1;
|
||||
optional int32 number = 3;
|
||||
optional Label label = 4;
|
||||
|
||||
// If type_name is set, this need not be set. If both this and type_name
|
||||
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
|
||||
optional Type type = 5;
|
||||
|
||||
// For message and enum types, this is the name of the type. If the name
|
||||
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
||||
// rules are used to find the type (i.e. first the nested types within this
|
||||
// message are searched, then within the parent, on up to the root
|
||||
// namespace).
|
||||
optional string type_name = 6;
|
||||
|
||||
// For extensions, this is the name of the type being extended. It is
|
||||
// resolved in the same manner as type_name.
|
||||
optional string extendee = 2;
|
||||
|
||||
// For numeric types, contains the original text representation of the value.
|
||||
// For booleans, "true" or "false".
|
||||
// For strings, contains the default text contents (not escaped in any way).
|
||||
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
||||
// TODO(kenton): Base-64 encode?
|
||||
optional string default_value = 7;
|
||||
|
||||
// If set, gives the index of a oneof in the containing type's oneof_decl
|
||||
// list. This field is a member of that oneof.
|
||||
optional int32 oneof_index = 9;
|
||||
|
||||
// JSON name of this field. The value is set by protocol compiler. If the
|
||||
// user has set a "json_name" option on this field, that option's value
|
||||
// will be used. Otherwise, it's deduced from the field's name by converting
|
||||
// it to camelCase.
|
||||
optional string json_name = 10;
|
||||
|
||||
optional FieldOptions options = 8;
|
||||
|
||||
// If true, this is a proto3 "optional". When a proto3 field is optional, it
|
||||
// tracks presence regardless of field type.
|
||||
//
|
||||
// When proto3_optional is true, this field must be belong to a oneof to
|
||||
// signal to old proto3 clients that presence is tracked for this field. This
|
||||
// oneof is known as a "synthetic" oneof, and this field must be its sole
|
||||
// member (each proto3 optional field gets its own synthetic oneof). Synthetic
|
||||
// oneofs exist in the descriptor only, and do not generate any API. Synthetic
|
||||
// oneofs must be ordered after all "real" oneofs.
|
||||
//
|
||||
// For message fields, proto3_optional doesn't create any semantic change,
|
||||
// since non-repeated message fields always track presence. However it still
|
||||
// indicates the semantic detail of whether the user wrote "optional" or not.
|
||||
// This can be useful for round-tripping the .proto file. For consistency we
|
||||
// give message fields a synthetic oneof also, even though it is not required
|
||||
// to track presence. This is especially important because the parser can't
|
||||
// tell if a field is a message or an enum, so it must always create a
|
||||
// synthetic oneof.
|
||||
//
|
||||
// Proto2 optional fields do not set this flag, because they already indicate
|
||||
// optional with `LABEL_OPTIONAL`.
|
||||
optional bool proto3_optional = 17;
|
||||
}
|
||||
|
||||
// Describes a oneof.
|
||||
message OneofDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional OneofOptions options = 2;
|
||||
}
|
||||
|
||||
// Describes an enum type.
|
||||
message EnumDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated EnumValueDescriptorProto value = 2;
|
||||
|
||||
optional EnumOptions options = 3;
|
||||
|
||||
// Range of reserved numeric values. Reserved values may not be used by
|
||||
// entries in the same enum. Reserved ranges may not overlap.
|
||||
//
|
||||
// Note that this is distinct from DescriptorProto.ReservedRange in that it
|
||||
// is inclusive such that it can appropriately represent the entire int32
|
||||
// domain.
|
||||
message EnumReservedRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Inclusive.
|
||||
}
|
||||
|
||||
// Range of reserved numeric values. Reserved numeric values may not be used
|
||||
// by enum values in the same enum declaration. Reserved ranges may not
|
||||
// overlap.
|
||||
repeated EnumReservedRange reserved_range = 4;
|
||||
|
||||
// Reserved enum value names, which may not be reused. A given name may only
|
||||
// be reserved once.
|
||||
repeated string reserved_name = 5;
|
||||
}
|
||||
|
||||
// Describes a value within an enum.
|
||||
message EnumValueDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
optional EnumValueOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a service.
|
||||
message ServiceDescriptorProto {
|
||||
optional string name = 1;
|
||||
repeated MethodDescriptorProto method = 2;
|
||||
|
||||
optional ServiceOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a method of a service.
|
||||
message MethodDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
// Input and output type names. These are resolved in the same way as
|
||||
// FieldDescriptorProto.type_name, but must refer to a message type.
|
||||
optional string input_type = 2;
|
||||
optional string output_type = 3;
|
||||
|
||||
optional MethodOptions options = 4;
|
||||
|
||||
// Identifies if client streams multiple client messages
|
||||
optional bool client_streaming = 5 [default = false];
|
||||
// Identifies if server streams multiple server messages
|
||||
optional bool server_streaming = 6 [default = false];
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
// Each of the definitions above may have "options" attached. These are
|
||||
// just annotations which may cause code to be generated slightly differently
|
||||
// or may contain hints for code that manipulates protocol messages.
|
||||
//
|
||||
// Clients may define custom options as extensions of the *Options messages.
|
||||
// These extensions may not yet be known at parsing time, so the parser cannot
|
||||
// store the values in them. Instead it stores them in a field in the *Options
|
||||
// message called uninterpreted_option. This field must have the same name
|
||||
// across all *Options messages. We then use this field to populate the
|
||||
// extensions when we build a descriptor, at which point all protos have been
|
||||
// parsed and so all extensions are known.
|
||||
//
|
||||
// Extension numbers for custom options may be chosen as follows:
|
||||
// * For options which will only be used within a single application or
|
||||
// organization, or for experimental options, use field numbers 50000
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail protobuf-global-extension-registry@google.com
|
||||
// to reserve extension numbers. Simply provide your project name (e.g.
|
||||
// Objective-C plugin) and your project website (if available) -- there's no
|
||||
// need to explain how you intend to use them. Usually you only need one
|
||||
// extension number. You can declare multiple options with only one extension
|
||||
// number by putting them in a sub-message. See the Custom Options section of
|
||||
// the docs for examples:
|
||||
// https://developers.google.com/protocol-buffers/docs/proto#options
|
||||
// If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
message FileOptions {
|
||||
|
||||
// Sets the Java package where classes generated from this .proto will be
|
||||
// placed. By default, the proto package is used, but this is often
|
||||
// inappropriate because proto packages do not normally start with backwards
|
||||
// domain names.
|
||||
optional string java_package = 1;
|
||||
|
||||
|
||||
// Controls the name of the wrapper Java class generated for the .proto file.
|
||||
// That class will always contain the .proto file's getDescriptor() method as
|
||||
// well as any top-level extensions defined in the .proto file.
|
||||
// If java_multiple_files is disabled, then all the other classes from the
|
||||
// .proto file will be nested inside the single wrapper outer class.
|
||||
optional string java_outer_classname = 8;
|
||||
|
||||
// If enabled, then the Java code generator will generate a separate .java
|
||||
// file for each top-level message, enum, and service defined in the .proto
|
||||
// file. Thus, these types will *not* be nested inside the wrapper class
|
||||
// named by java_outer_classname. However, the wrapper class will still be
|
||||
// generated to contain the file's getDescriptor() method as well as any
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default = false];
|
||||
|
||||
// This option does nothing.
|
||||
optional bool java_generate_equals_and_hash = 20 [deprecated=true];
|
||||
|
||||
// If set true, then the Java2 code generator will generate code that
|
||||
// throws an exception whenever an attempt is made to assign a non-UTF-8
|
||||
// byte sequence to a string field.
|
||||
// Message reflection will do the same.
|
||||
// However, an extension field still accepts non-UTF-8 byte sequences.
|
||||
// This option has no effect on when used with the lite runtime.
|
||||
optional bool java_string_check_utf8 = 27 [default = false];
|
||||
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
// etc.
|
||||
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
||||
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default = SPEED];
|
||||
|
||||
// Sets the Go package where structs generated from this .proto will be
|
||||
// placed. If omitted, the Go package will be derived from the following:
|
||||
// - The basename of the package import path, if provided.
|
||||
// - Otherwise, the package statement in the .proto file, if present.
|
||||
// - Otherwise, the basename of the .proto file, without extension.
|
||||
optional string go_package = 11;
|
||||
|
||||
|
||||
|
||||
|
||||
// Should generic services be generated in each language? "Generic" services
|
||||
// are not specific to any particular RPC system. They are generated by the
|
||||
// main code generators in each language (without additional plugins).
|
||||
// Generic services were the only kind of service generation supported by
|
||||
// early versions of google.protobuf.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. Therefore,
|
||||
// these default to false. Old code which depends on generic services should
|
||||
// explicitly set them to true.
|
||||
optional bool cc_generic_services = 16 [default = false];
|
||||
optional bool java_generic_services = 17 [default = false];
|
||||
optional bool py_generic_services = 18 [default = false];
|
||||
optional bool php_generic_services = 42 [default = false];
|
||||
|
||||
// Is this file deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for everything in the file, or it will be completely ignored; in the very
|
||||
// least, this is a formalization for deprecating files.
|
||||
optional bool deprecated = 23 [default = false];
|
||||
|
||||
// Enables the use of arenas for the proto messages in this file. This applies
|
||||
// only to generated classes for C++.
|
||||
optional bool cc_enable_arenas = 31 [default = true];
|
||||
|
||||
|
||||
// Sets the objective c class prefix which is prepended to all objective c
|
||||
// generated classes from this .proto. There is no default.
|
||||
optional string objc_class_prefix = 36;
|
||||
|
||||
// Namespace for generated classes; defaults to the package.
|
||||
optional string csharp_namespace = 37;
|
||||
|
||||
// By default Swift generators will take the proto package and CamelCase it
|
||||
// replacing '.' with underscore and use that to prefix the types/symbols
|
||||
// defined. When this options is provided, they will use this value instead
|
||||
// to prefix the types/symbols defined.
|
||||
optional string swift_prefix = 39;
|
||||
|
||||
// Sets the php class prefix which is prepended to all php generated classes
|
||||
// from this .proto. Default is empty.
|
||||
optional string php_class_prefix = 40;
|
||||
|
||||
// Use this option to change the namespace of php generated classes. Default
|
||||
// is empty. When this option is empty, the package name will be used for
|
||||
// determining the namespace.
|
||||
optional string php_namespace = 41;
|
||||
|
||||
// Use this option to change the namespace of php generated metadata classes.
|
||||
// Default is empty. When this option is empty, the proto file name will be
|
||||
// used for determining the namespace.
|
||||
optional string php_metadata_namespace = 44;
|
||||
|
||||
// Use this option to change the package of ruby generated classes. Default
|
||||
// is empty. When this option is not set, the package name will be used for
|
||||
// determining the ruby package.
|
||||
optional string ruby_package = 45;
|
||||
|
||||
|
||||
// The parser stores options it doesn't recognize here.
|
||||
// See the documentation for the "Options" section above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message.
|
||||
// See the documentation for the "Options" section above.
|
||||
extensions 1000 to max;
|
||||
|
||||
reserved 38;
|
||||
}
|
||||
|
||||
message MessageOptions {
|
||||
// Set true to use the old proto1 MessageSet wire format for extensions.
|
||||
// This is provided for backwards-compatibility with the MessageSet wire
|
||||
// format. You should not use this for any other reason: It's less
|
||||
// efficient, has fewer features, and is more complicated.
|
||||
//
|
||||
// The message must be defined exactly as follows:
|
||||
// message Foo {
|
||||
// option message_set_wire_format = true;
|
||||
// extensions 4 to max;
|
||||
// }
|
||||
// Note that the message cannot have any defined fields; MessageSets only
|
||||
// have extensions.
|
||||
//
|
||||
// All extensions of your type must be singular messages; e.g. they cannot
|
||||
// be int32s, enums, or repeated messages.
|
||||
//
|
||||
// Because this is an option, the above two restrictions are not enforced by
|
||||
// the protocol compiler.
|
||||
optional bool message_set_wire_format = 1 [default = false];
|
||||
|
||||
// Disables the generation of the standard "descriptor()" accessor, which can
|
||||
// conflict with a field of the same name. This is meant to make migration
|
||||
// from proto1 easier; new code should avoid fields named "descriptor".
|
||||
optional bool no_standard_descriptor_accessor = 2 [default = false];
|
||||
|
||||
// Is this message deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the message, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating messages.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
reserved 4, 5, 6;
|
||||
|
||||
// Whether the message is an automatically generated map entry type for the
|
||||
// maps field.
|
||||
//
|
||||
// For maps fields:
|
||||
// map<KeyType, ValueType> map_field = 1;
|
||||
// The parsed descriptor looks like:
|
||||
// message MapFieldEntry {
|
||||
// option map_entry = true;
|
||||
// optional KeyType key = 1;
|
||||
// optional ValueType value = 2;
|
||||
// }
|
||||
// repeated MapFieldEntry map_field = 1;
|
||||
//
|
||||
// Implementations may choose not to generate the map_entry=true message, but
|
||||
// use a native map in the target language to hold the keys and values.
|
||||
// The reflection APIs in such implementations still need to work as
|
||||
// if the field is a repeated message field.
|
||||
//
|
||||
// NOTE: Do not set the option in .proto files. Always use the maps syntax
|
||||
// instead. The option should only be implicitly set by the proto compiler
|
||||
// parser.
|
||||
optional bool map_entry = 7;
|
||||
|
||||
reserved 8; // javalite_serializable
|
||||
reserved 9; // javanano_as_lite
|
||||
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message FieldOptions {
|
||||
// The ctype option instructs the C++ code generator to use a different
|
||||
// representation of the field than it normally would. See the specific
|
||||
// options below. This option is not yet implemented in the open source
|
||||
// release -- sorry, we'll try to include it in a future version!
|
||||
optional CType ctype = 1 [default = STRING];
|
||||
enum CType {
|
||||
// Default mode.
|
||||
STRING = 0;
|
||||
|
||||
CORD = 1;
|
||||
|
||||
STRING_PIECE = 2;
|
||||
}
|
||||
// The packed option can be enabled for repeated primitive fields to enable
|
||||
// a more efficient representation on the wire. Rather than repeatedly
|
||||
// writing the tag and type for each element, the entire array is encoded as
|
||||
// a single length-delimited blob. In proto3, only explicit setting it to
|
||||
// false will avoid using packed encoding.
|
||||
optional bool packed = 2;
|
||||
|
||||
// The jstype option determines the JavaScript type used for values of the
|
||||
// field. The option is permitted only for 64 bit integral and fixed types
|
||||
// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
|
||||
// is represented as JavaScript string, which avoids loss of precision that
|
||||
// can happen when a large value is converted to a floating point JavaScript.
|
||||
// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
|
||||
// use the JavaScript "number" type. The behavior of the default option
|
||||
// JS_NORMAL is implementation dependent.
|
||||
//
|
||||
// This option is an enum to permit additional types to be added, e.g.
|
||||
// goog.math.Integer.
|
||||
optional JSType jstype = 6 [default = JS_NORMAL];
|
||||
enum JSType {
|
||||
// Use the default type.
|
||||
JS_NORMAL = 0;
|
||||
|
||||
// Use JavaScript strings.
|
||||
JS_STRING = 1;
|
||||
|
||||
// Use JavaScript numbers.
|
||||
JS_NUMBER = 2;
|
||||
}
|
||||
|
||||
// Should this field be parsed lazily? Lazy applies only to message-type
|
||||
// fields. It means that when the outer message is initially parsed, the
|
||||
// inner message's contents will not be parsed but instead stored in encoded
|
||||
// form. The inner message will actually be parsed when it is first accessed.
|
||||
//
|
||||
// This is only a hint. Implementations are free to choose whether to use
|
||||
// eager or lazy parsing regardless of the value of this option. However,
|
||||
// setting this option true suggests that the protocol author believes that
|
||||
// using lazy parsing on this field is worth the additional bookkeeping
|
||||
// overhead typically needed to implement it.
|
||||
//
|
||||
// This option does not affect the public interface of any generated code;
|
||||
// all method signatures remain the same. Furthermore, thread-safety of the
|
||||
// interface is not affected by this option; const methods remain safe to
|
||||
// call from multiple threads concurrently, while non-const methods continue
|
||||
// to require exclusive access.
|
||||
//
|
||||
//
|
||||
// Note that implementations may choose not to check required fields within
|
||||
// a lazy sub-message. That is, calling IsInitialized() on the outer message
|
||||
// may return true even if the inner message has missing required fields.
|
||||
// This is necessary because otherwise the inner message would have to be
|
||||
// parsed in order to perform the check, defeating the purpose of lazy
|
||||
// parsing. An implementation which chooses not to check required fields
|
||||
// must be consistent about it. That is, for any particular sub-message, the
|
||||
// implementation must either *always* check its required fields, or *never*
|
||||
// check its required fields, regardless of whether or not the message has
|
||||
// been parsed.
|
||||
optional bool lazy = 5 [default = false];
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating fields.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
// For Google-internal migration only. Do not use.
|
||||
optional bool weak = 10 [default = false];
|
||||
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
|
||||
reserved 4; // removed jtype
|
||||
}
|
||||
|
||||
message OneofOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// Set this option to true to allow mapping different tag names to the same
|
||||
// value.
|
||||
optional bool allow_alias = 2;
|
||||
|
||||
// Is this enum deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating enums.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
reserved 5; // javanano_as_lite
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumValueOptions {
|
||||
// Is this enum value deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum value, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating enum values.
|
||||
optional bool deprecated = 1 [default = false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message ServiceOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this service deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the service, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating services.
|
||||
optional bool deprecated = 33 [default = false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MethodOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this method deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the method, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating methods.
|
||||
optional bool deprecated = 33 [default = false];
|
||||
|
||||
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
|
||||
// or neither? HTTP based RPC implementation may choose GET verb for safe
|
||||
// methods, and PUT verb for idempotent methods instead of the default POST.
|
||||
enum IdempotencyLevel {
|
||||
IDEMPOTENCY_UNKNOWN = 0;
|
||||
NO_SIDE_EFFECTS = 1; // implies idempotent
|
||||
IDEMPOTENT = 2; // idempotent, but may have side effects
|
||||
}
|
||||
optional IdempotencyLevel idempotency_level = 34
|
||||
[default = IDEMPOTENCY_UNKNOWN];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
|
||||
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
|
||||
// in them.
|
||||
message UninterpretedOption {
|
||||
// The name of the uninterpreted option. Each string represents a segment in
|
||||
// a dot-separated name. is_extension is true iff a segment represents an
|
||||
// extension (denoted with parentheses in options specs in .proto files).
|
||||
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
|
||||
// "foo.(bar.baz).qux".
|
||||
message NamePart {
|
||||
required string name_part = 1;
|
||||
required bool is_extension = 2;
|
||||
}
|
||||
repeated NamePart name = 2;
|
||||
|
||||
// The value of the uninterpreted option, in whatever type the tokenizer
|
||||
// identified it as during parsing. Exactly one of these should be set.
|
||||
optional string identifier_value = 3;
|
||||
optional uint64 positive_int_value = 4;
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
optional string aggregate_value = 8;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Optional source code info
|
||||
|
||||
// Encapsulates information about the original source file from which a
|
||||
// FileDescriptorProto was generated.
|
||||
message SourceCodeInfo {
|
||||
// A Location identifies a piece of source code in a .proto file which
|
||||
// corresponds to a particular definition. This information is intended
|
||||
// to be useful to IDEs, code indexers, documentation generators, and similar
|
||||
// tools.
|
||||
//
|
||||
// For example, say we have a file like:
|
||||
// message Foo {
|
||||
// optional string foo = 1;
|
||||
// }
|
||||
// Let's look at just the field definition:
|
||||
// optional string foo = 1;
|
||||
// ^ ^^ ^^ ^ ^^^
|
||||
// a bc de f ghi
|
||||
// We have the following locations:
|
||||
// span path represents
|
||||
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
|
||||
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
|
||||
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
|
||||
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
|
||||
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
|
||||
//
|
||||
// Notes:
|
||||
// - A location may refer to a repeated field itself (i.e. not to any
|
||||
// particular index within it). This is used whenever a set of elements are
|
||||
// logically enclosed in a single code segment. For example, an entire
|
||||
// extend block (possibly containing multiple extension definitions) will
|
||||
// have an outer location whose path refers to the "extensions" repeated
|
||||
// field without an index.
|
||||
// - Multiple locations may have the same path. This happens when a single
|
||||
// logical declaration is spread out across multiple places. The most
|
||||
// obvious example is the "extend" block again -- there may be multiple
|
||||
// extend blocks in the same scope, each of which will have the same path.
|
||||
// - A location's span is not always a subset of its parent's span. For
|
||||
// example, the "extendee" of an extension declaration appears at the
|
||||
// beginning of the "extend" block and is shared by all extensions within
|
||||
// the block.
|
||||
// - Just because a location's span is a subset of some other location's span
|
||||
// does not mean that it is a descendant. For example, a "group" defines
|
||||
// both a type and a field in a single declaration. Thus, the locations
|
||||
// corresponding to the type and field and their components will overlap.
|
||||
// - Code which tries to interpret locations should probably be designed to
|
||||
// ignore those that it doesn't understand, as more types of locations could
|
||||
// be recorded in the future.
|
||||
repeated Location location = 1;
|
||||
message Location {
|
||||
// Identifies which part of the FileDescriptorProto was defined at this
|
||||
// location.
|
||||
//
|
||||
// Each element is a field number or an index. They form a path from
|
||||
// the root FileDescriptorProto to the place where the definition. For
|
||||
// example, this path:
|
||||
// [ 4, 3, 2, 7, 1 ]
|
||||
// refers to:
|
||||
// file.message_type(3) // 4, 3
|
||||
// .field(7) // 2, 7
|
||||
// .name() // 1
|
||||
// This is because FileDescriptorProto.message_type has field number 4:
|
||||
// repeated DescriptorProto message_type = 4;
|
||||
// and DescriptorProto.field has field number 2:
|
||||
// repeated FieldDescriptorProto field = 2;
|
||||
// and FieldDescriptorProto.name has field number 1:
|
||||
// optional string name = 1;
|
||||
//
|
||||
// Thus, the above path gives the location of a field name. If we removed
|
||||
// the last element:
|
||||
// [ 4, 3, 2, 7 ]
|
||||
// this path refers to the whole field declaration (from the beginning
|
||||
// of the label to the terminating semicolon).
|
||||
repeated int32 path = 1 [packed = true];
|
||||
|
||||
// Always has exactly three or four elements: start line, start column,
|
||||
// end line (optional, otherwise assumed same as start line), end column.
|
||||
// These are packed into a single field for efficiency. Note that line
|
||||
// and column numbers are zero-based -- typically you will want to add
|
||||
// 1 to each before displaying to a user.
|
||||
repeated int32 span = 2 [packed = true];
|
||||
|
||||
// If this SourceCodeInfo represents a complete declaration, these are any
|
||||
// comments appearing before and after the declaration which appear to be
|
||||
// attached to the declaration.
|
||||
//
|
||||
// A series of line comments appearing on consecutive lines, with no other
|
||||
// tokens appearing on those lines, will be treated as a single comment.
|
||||
//
|
||||
// leading_detached_comments will keep paragraphs of comments that appear
|
||||
// before (but not connected to) the current element. Each paragraph,
|
||||
// separated by empty lines, will be one comment element in the repeated
|
||||
// field.
|
||||
//
|
||||
// Only the comment content is provided; comment markers (e.g. //) are
|
||||
// stripped out. For block comments, leading whitespace and an asterisk
|
||||
// will be stripped from the beginning of each line other than the first.
|
||||
// Newlines are included in the output.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// optional int32 foo = 1; // Comment attached to foo.
|
||||
// // Comment attached to bar.
|
||||
// optional int32 bar = 2;
|
||||
//
|
||||
// optional string baz = 3;
|
||||
// // Comment attached to baz.
|
||||
// // Another line attached to baz.
|
||||
//
|
||||
// // Comment attached to qux.
|
||||
// //
|
||||
// // Another line attached to qux.
|
||||
// optional double qux = 4;
|
||||
//
|
||||
// // Detached comment for corge. This is not leading or trailing comments
|
||||
// // to qux or corge because there are blank lines separating it from
|
||||
// // both.
|
||||
//
|
||||
// // Detached comment for corge paragraph 2.
|
||||
//
|
||||
// optional string corge = 5;
|
||||
// /* Block comment attached
|
||||
// * to corge. Leading asterisks
|
||||
// * will be removed. */
|
||||
// /* Block comment attached to
|
||||
// * grault. */
|
||||
// optional int32 grault = 6;
|
||||
//
|
||||
// // ignored detached comments.
|
||||
optional string leading_comments = 3;
|
||||
optional string trailing_comments = 4;
|
||||
repeated string leading_detached_comments = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Describes the relationship between generated code and its original source
|
||||
// file. A GeneratedCodeInfo message is associated with only one generated
|
||||
// source file, but may contain references to different source .proto files.
|
||||
message GeneratedCodeInfo {
|
||||
// An Annotation connects some span of text in generated code to an element
|
||||
// of its generating .proto file.
|
||||
repeated Annotation annotation = 1;
|
||||
message Annotation {
|
||||
// Identifies the element in the original source .proto file. This field
|
||||
// is formatted the same as SourceCodeInfo.Location.path.
|
||||
repeated int32 path = 1 [packed = true];
|
||||
|
||||
// Identifies the filesystem path to the original source .proto.
|
||||
optional string source_file = 2;
|
||||
|
||||
// Identifies the starting offset in bytes in the generated code
|
||||
// that relates to the identified object.
|
||||
optional int32 begin = 3;
|
||||
|
||||
// Identifies the ending offset in bytes in the generated code that
|
||||
// relates to the identified offset. The end offset should be one past
|
||||
// the last relevant byte (so the length of the text = end - begin).
|
||||
optional int32 end = 4;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/durationpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DurationProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Timestamp end = ...;
|
||||
// Duration duration = ...;
|
||||
//
|
||||
// duration.seconds = end.seconds - start.seconds;
|
||||
// duration.nanos = end.nanos - start.nanos;
|
||||
//
|
||||
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||
// duration.seconds += 1;
|
||||
// duration.nanos -= 1000000000;
|
||||
// } else if (duration.seconds > 0 && duration.nanos < 0) {
|
||||
// duration.seconds -= 1;
|
||||
// duration.nanos += 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Duration duration = ...;
|
||||
// Timestamp end = ...;
|
||||
//
|
||||
// end.seconds = start.seconds + duration.seconds;
|
||||
// end.nanos = start.nanos + duration.nanos;
|
||||
//
|
||||
// if (end.nanos < 0) {
|
||||
// end.seconds -= 1;
|
||||
// end.nanos += 1000000000;
|
||||
// } else if (end.nanos >= 1000000000) {
|
||||
// end.seconds += 1;
|
||||
// end.nanos -= 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||
//
|
||||
// td = datetime.timedelta(days=3, minutes=10)
|
||||
// duration = Duration()
|
||||
// duration.FromTimedelta(td)
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Duration type is encoded as a string rather than an
|
||||
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
// microsecond should be expressed in JSON format as "3.000001s".
|
||||
//
|
||||
//
|
||||
message Duration {
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
int64 seconds = 1;
|
||||
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/emptypb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "EmptyProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// A generic empty message that you can re-use to avoid defining duplicated
|
||||
// empty messages in your APIs. A typical example is to use it as the request
|
||||
// or the response type of an API method. For instance:
|
||||
//
|
||||
// service Foo {
|
||||
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
// }
|
||||
//
|
||||
// The JSON representation for `Empty` is empty JSON object `{}`.
|
||||
message Empty {}
|
||||
@ -0,0 +1,245 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "FieldMaskProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb";
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// `FieldMask` represents a set of symbolic field paths, for example:
|
||||
//
|
||||
// paths: "f.a"
|
||||
// paths: "f.b.d"
|
||||
//
|
||||
// Here `f` represents a field in some root message, `a` and `b`
|
||||
// fields in the message found in `f`, and `d` a field found in the
|
||||
// message in `f.b`.
|
||||
//
|
||||
// Field masks are used to specify a subset of fields that should be
|
||||
// returned by a get operation or modified by an update operation.
|
||||
// Field masks also have a custom JSON encoding (see below).
|
||||
//
|
||||
// # Field Masks in Projections
|
||||
//
|
||||
// When used in the context of a projection, a response message or
|
||||
// sub-message is filtered by the API to only contain those fields as
|
||||
// specified in the mask. For example, if the mask in the previous
|
||||
// example is applied to a response message as follows:
|
||||
//
|
||||
// f {
|
||||
// a : 22
|
||||
// b {
|
||||
// d : 1
|
||||
// x : 2
|
||||
// }
|
||||
// y : 13
|
||||
// }
|
||||
// z: 8
|
||||
//
|
||||
// The result will not contain specific values for fields x,y and z
|
||||
// (their value will be set to the default, and omitted in proto text
|
||||
// output):
|
||||
//
|
||||
//
|
||||
// f {
|
||||
// a : 22
|
||||
// b {
|
||||
// d : 1
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// A repeated field is not allowed except at the last position of a
|
||||
// paths string.
|
||||
//
|
||||
// If a FieldMask object is not present in a get operation, the
|
||||
// operation applies to all fields (as if a FieldMask of all fields
|
||||
// had been specified).
|
||||
//
|
||||
// Note that a field mask does not necessarily apply to the
|
||||
// top-level response message. In case of a REST get operation, the
|
||||
// field mask applies directly to the response, but in case of a REST
|
||||
// list operation, the mask instead applies to each individual message
|
||||
// in the returned resource list. In case of a REST custom method,
|
||||
// other definitions may be used. Where the mask applies will be
|
||||
// clearly documented together with its declaration in the API. In
|
||||
// any case, the effect on the returned resource/resources is required
|
||||
// behavior for APIs.
|
||||
//
|
||||
// # Field Masks in Update Operations
|
||||
//
|
||||
// A field mask in update operations specifies which fields of the
|
||||
// targeted resource are going to be updated. The API is required
|
||||
// to only change the values of the fields as specified in the mask
|
||||
// and leave the others untouched. If a resource is passed in to
|
||||
// describe the updated values, the API ignores the values of all
|
||||
// fields not covered by the mask.
|
||||
//
|
||||
// If a repeated field is specified for an update operation, new values will
|
||||
// be appended to the existing repeated field in the target resource. Note that
|
||||
// a repeated field is only allowed in the last position of a `paths` string.
|
||||
//
|
||||
// If a sub-message is specified in the last position of the field mask for an
|
||||
// update operation, then new value will be merged into the existing sub-message
|
||||
// in the target resource.
|
||||
//
|
||||
// For example, given the target message:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 1
|
||||
// x: 2
|
||||
// }
|
||||
// c: [1]
|
||||
// }
|
||||
//
|
||||
// And an update message:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 10
|
||||
// }
|
||||
// c: [2]
|
||||
// }
|
||||
//
|
||||
// then if the field mask is:
|
||||
//
|
||||
// paths: ["f.b", "f.c"]
|
||||
//
|
||||
// then the result will be:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 10
|
||||
// x: 2
|
||||
// }
|
||||
// c: [1, 2]
|
||||
// }
|
||||
//
|
||||
// An implementation may provide options to override this default behavior for
|
||||
// repeated and message fields.
|
||||
//
|
||||
// In order to reset a field's value to the default, the field must
|
||||
// be in the mask and set to the default value in the provided resource.
|
||||
// Hence, in order to reset all fields of a resource, provide a default
|
||||
// instance of the resource and set all fields in the mask, or do
|
||||
// not provide a mask as described below.
|
||||
//
|
||||
// If a field mask is not present on update, the operation applies to
|
||||
// all fields (as if a field mask of all fields has been specified).
|
||||
// Note that in the presence of schema evolution, this may mean that
|
||||
// fields the client does not know and has therefore not filled into
|
||||
// the request will be reset to their default. If this is unwanted
|
||||
// behavior, a specific service may require a client to always specify
|
||||
// a field mask, producing an error if not.
|
||||
//
|
||||
// As with get operations, the location of the resource which
|
||||
// describes the updated values in the request message depends on the
|
||||
// operation kind. In any case, the effect of the field mask is
|
||||
// required to be honored by the API.
|
||||
//
|
||||
// ## Considerations for HTTP REST
|
||||
//
|
||||
// The HTTP kind of an update operation which uses a field mask must
|
||||
// be set to PATCH instead of PUT in order to satisfy HTTP semantics
|
||||
// (PUT must only be used for full updates).
|
||||
//
|
||||
// # JSON Encoding of Field Masks
|
||||
//
|
||||
// In JSON, a field mask is encoded as a single string where paths are
|
||||
// separated by a comma. Fields name in each path are converted
|
||||
// to/from lower-camel naming conventions.
|
||||
//
|
||||
// As an example, consider the following message declarations:
|
||||
//
|
||||
// message Profile {
|
||||
// User user = 1;
|
||||
// Photo photo = 2;
|
||||
// }
|
||||
// message User {
|
||||
// string display_name = 1;
|
||||
// string address = 2;
|
||||
// }
|
||||
//
|
||||
// In proto a field mask for `Profile` may look as such:
|
||||
//
|
||||
// mask {
|
||||
// paths: "user.display_name"
|
||||
// paths: "photo"
|
||||
// }
|
||||
//
|
||||
// In JSON, the same mask is represented as below:
|
||||
//
|
||||
// {
|
||||
// mask: "user.displayName,photo"
|
||||
// }
|
||||
//
|
||||
// # Field Masks and Oneof Fields
|
||||
//
|
||||
// Field masks treat fields in oneofs just as regular fields. Consider the
|
||||
// following message:
|
||||
//
|
||||
// message SampleMessage {
|
||||
// oneof test_oneof {
|
||||
// string name = 4;
|
||||
// SubMessage sub_message = 9;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The field mask can be:
|
||||
//
|
||||
// mask {
|
||||
// paths: "name"
|
||||
// }
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// mask {
|
||||
// paths: "sub_message"
|
||||
// }
|
||||
//
|
||||
// Note that oneof type names ("test_oneof" in this case) cannot be used in
|
||||
// paths.
|
||||
//
|
||||
// ## Field Mask Verification
|
||||
//
|
||||
// The implementation of any API method which has a FieldMask type field in the
|
||||
// request should verify the included field paths, and return an
|
||||
// `INVALID_ARGUMENT` error if any path is unmappable.
|
||||
message FieldMask {
|
||||
// The set of field mask paths.
|
||||
repeated string paths = 1;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "SourceContextProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb";
|
||||
|
||||
// `SourceContext` represents information about the source of a
|
||||
// protobuf element, like the file in which it is defined.
|
||||
message SourceContext {
|
||||
// The path-qualified name of the .proto file that contained the associated
|
||||
// protobuf element. For example: `"google/protobuf/source_context.proto"`.
|
||||
string file_name = 1;
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/structpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "StructProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// `Struct` represents a structured data value, consisting of fields
|
||||
// which map to dynamically typed values. In some languages, `Struct`
|
||||
// might be supported by a native representation. For example, in
|
||||
// scripting languages like JS a struct is represented as an
|
||||
// object. The details of that representation are described together
|
||||
// with the proto support for the language.
|
||||
//
|
||||
// The JSON representation for `Struct` is JSON object.
|
||||
message Struct {
|
||||
// Unordered map of dynamically typed values.
|
||||
map<string, Value> fields = 1;
|
||||
}
|
||||
|
||||
// `Value` represents a dynamically typed value which can be either
|
||||
// null, a number, a string, a boolean, a recursive struct value, or a
|
||||
// list of values. A producer of value is expected to set one of that
|
||||
// variants, absence of any variant indicates an error.
|
||||
//
|
||||
// The JSON representation for `Value` is JSON value.
|
||||
message Value {
|
||||
// The kind of value.
|
||||
oneof kind {
|
||||
// Represents a null value.
|
||||
NullValue null_value = 1;
|
||||
// Represents a double value.
|
||||
double number_value = 2;
|
||||
// Represents a string value.
|
||||
string string_value = 3;
|
||||
// Represents a boolean value.
|
||||
bool bool_value = 4;
|
||||
// Represents a structured value.
|
||||
Struct struct_value = 5;
|
||||
// Represents a repeated `Value`.
|
||||
ListValue list_value = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// `NullValue` is a singleton enumeration to represent the null value for the
|
||||
// `Value` type union.
|
||||
//
|
||||
// The JSON representation for `NullValue` is JSON `null`.
|
||||
enum NullValue {
|
||||
// Null value.
|
||||
NULL_VALUE = 0;
|
||||
}
|
||||
|
||||
// `ListValue` is a wrapper around a repeated field of values.
|
||||
//
|
||||
// The JSON representation for `ListValue` is JSON array.
|
||||
message ListValue {
|
||||
// Repeated field of dynamically typed values.
|
||||
repeated Value values = 1;
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/timestamppb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "TimestampProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// A Timestamp represents a point in time independent of any time zone or local
|
||||
// calendar, encoded as a count of seconds and fractions of seconds at
|
||||
// nanosecond resolution. The count is relative to an epoch at UTC midnight on
|
||||
// January 1, 1970, in the proleptic Gregorian calendar which extends the
|
||||
// Gregorian calendar backwards to year one.
|
||||
//
|
||||
// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
|
||||
// second table is needed for interpretation, using a [24-hour linear
|
||||
// smear](https://developers.google.com/time/smear).
|
||||
//
|
||||
// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
|
||||
// restricting to that range, we ensure that we can convert to and from [RFC
|
||||
// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(time(NULL));
|
||||
// timestamp.set_nanos(0);
|
||||
//
|
||||
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||
//
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, NULL);
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(tv.tv_sec);
|
||||
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||
//
|
||||
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||
//
|
||||
// FILETIME ft;
|
||||
// GetSystemTimeAsFileTime(&ft);
|
||||
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
//
|
||||
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||
//
|
||||
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||
//
|
||||
// long millis = System.currentTimeMillis();
|
||||
//
|
||||
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||
//
|
||||
//
|
||||
// Example 5: Compute Timestamp from Java `Instant.now()`.
|
||||
//
|
||||
// Instant now = Instant.now();
|
||||
//
|
||||
// Timestamp timestamp =
|
||||
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
|
||||
// .setNanos(now.getNano()).build();
|
||||
//
|
||||
//
|
||||
// Example 6: Compute Timestamp from current time in Python.
|
||||
//
|
||||
// timestamp = Timestamp()
|
||||
// timestamp.GetCurrentTime()
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Timestamp type is encoded as a string in the
|
||||
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
// where {year} is always expressed using four digits while {month}, {day},
|
||||
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
// is required. A proto3 JSON serializer should always use UTC (as indicated by
|
||||
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
|
||||
// able to accept both UTC and other timezones (as indicated by an offset).
|
||||
//
|
||||
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
// 01:30 UTC on January 15, 2017.
|
||||
//
|
||||
// In JavaScript, one can convert a Date object to this format using the
|
||||
// standard
|
||||
// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||
// to this format using
|
||||
// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
|
||||
// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
|
||||
// the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
|
||||
// ) to obtain a formatter capable of generating timestamps in this format.
|
||||
//
|
||||
//
|
||||
message Timestamp {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/source_context.proto";
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "TypeProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option go_package = "google.golang.org/protobuf/types/known/typepb";
|
||||
|
||||
// A protocol buffer message type.
|
||||
message Type {
|
||||
// The fully qualified message name.
|
||||
string name = 1;
|
||||
// The list of fields.
|
||||
repeated Field fields = 2;
|
||||
// The list of types appearing in `oneof` definitions in this type.
|
||||
repeated string oneofs = 3;
|
||||
// The protocol buffer options.
|
||||
repeated Option options = 4;
|
||||
// The source context.
|
||||
SourceContext source_context = 5;
|
||||
// The source syntax.
|
||||
Syntax syntax = 6;
|
||||
}
|
||||
|
||||
// A single field of a message type.
|
||||
message Field {
|
||||
// Basic field types.
|
||||
enum Kind {
|
||||
// Field type unknown.
|
||||
TYPE_UNKNOWN = 0;
|
||||
// Field type double.
|
||||
TYPE_DOUBLE = 1;
|
||||
// Field type float.
|
||||
TYPE_FLOAT = 2;
|
||||
// Field type int64.
|
||||
TYPE_INT64 = 3;
|
||||
// Field type uint64.
|
||||
TYPE_UINT64 = 4;
|
||||
// Field type int32.
|
||||
TYPE_INT32 = 5;
|
||||
// Field type fixed64.
|
||||
TYPE_FIXED64 = 6;
|
||||
// Field type fixed32.
|
||||
TYPE_FIXED32 = 7;
|
||||
// Field type bool.
|
||||
TYPE_BOOL = 8;
|
||||
// Field type string.
|
||||
TYPE_STRING = 9;
|
||||
// Field type group. Proto2 syntax only, and deprecated.
|
||||
TYPE_GROUP = 10;
|
||||
// Field type message.
|
||||
TYPE_MESSAGE = 11;
|
||||
// Field type bytes.
|
||||
TYPE_BYTES = 12;
|
||||
// Field type uint32.
|
||||
TYPE_UINT32 = 13;
|
||||
// Field type enum.
|
||||
TYPE_ENUM = 14;
|
||||
// Field type sfixed32.
|
||||
TYPE_SFIXED32 = 15;
|
||||
// Field type sfixed64.
|
||||
TYPE_SFIXED64 = 16;
|
||||
// Field type sint32.
|
||||
TYPE_SINT32 = 17;
|
||||
// Field type sint64.
|
||||
TYPE_SINT64 = 18;
|
||||
}
|
||||
|
||||
// Whether a field is optional, required, or repeated.
|
||||
enum Cardinality {
|
||||
// For fields with unknown cardinality.
|
||||
CARDINALITY_UNKNOWN = 0;
|
||||
// For optional fields.
|
||||
CARDINALITY_OPTIONAL = 1;
|
||||
// For required fields. Proto2 syntax only.
|
||||
CARDINALITY_REQUIRED = 2;
|
||||
// For repeated fields.
|
||||
CARDINALITY_REPEATED = 3;
|
||||
}
|
||||
|
||||
// The field type.
|
||||
Kind kind = 1;
|
||||
// The field cardinality.
|
||||
Cardinality cardinality = 2;
|
||||
// The field number.
|
||||
int32 number = 3;
|
||||
// The field name.
|
||||
string name = 4;
|
||||
// The field type URL, without the scheme, for message or enumeration
|
||||
// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
|
||||
string type_url = 6;
|
||||
// The index of the field type in `Type.oneofs`, for message or enumeration
|
||||
// types. The first type has index 1; zero means the type is not in the list.
|
||||
int32 oneof_index = 7;
|
||||
// Whether to use alternative packed wire representation.
|
||||
bool packed = 8;
|
||||
// The protocol buffer options.
|
||||
repeated Option options = 9;
|
||||
// The field JSON name.
|
||||
string json_name = 10;
|
||||
// The string value of the default value of this field. Proto2 syntax only.
|
||||
string default_value = 11;
|
||||
}
|
||||
|
||||
// Enum type definition.
|
||||
message Enum {
|
||||
// Enum type name.
|
||||
string name = 1;
|
||||
// Enum value definitions.
|
||||
repeated EnumValue enumvalue = 2;
|
||||
// Protocol buffer options.
|
||||
repeated Option options = 3;
|
||||
// The source context.
|
||||
SourceContext source_context = 4;
|
||||
// The source syntax.
|
||||
Syntax syntax = 5;
|
||||
}
|
||||
|
||||
// Enum value definition.
|
||||
message EnumValue {
|
||||
// Enum value name.
|
||||
string name = 1;
|
||||
// Enum value number.
|
||||
int32 number = 2;
|
||||
// Protocol buffer options.
|
||||
repeated Option options = 3;
|
||||
}
|
||||
|
||||
// A protocol buffer option, which can be attached to a message, field,
|
||||
// enumeration, etc.
|
||||
message Option {
|
||||
// The option's name. For protobuf built-in options (options defined in
|
||||
// descriptor.proto), this is the short name. For example, `"map_entry"`.
|
||||
// For custom options, it should be the fully-qualified name. For example,
|
||||
// `"google.api.http"`.
|
||||
string name = 1;
|
||||
// The option's value packed in an Any message. If the value is a primitive,
|
||||
// the corresponding wrapper type defined in google/protobuf/wrappers.proto
|
||||
// should be used. If the value is an enum, it should be stored as an int32
|
||||
// value using the google.protobuf.Int32Value type.
|
||||
Any value = 2;
|
||||
}
|
||||
|
||||
// The syntax in which a protocol buffer element is defined.
|
||||
enum Syntax {
|
||||
// Syntax `proto2`.
|
||||
SYNTAX_PROTO2 = 0;
|
||||
// Syntax `proto3`.
|
||||
SYNTAX_PROTO3 = 1;
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Wrappers for primitive (non-message) types. These types are useful
|
||||
// for embedding primitives in the `google.protobuf.Any` type and for places
|
||||
// where we need to distinguish between the absence of a primitive
|
||||
// typed field and its default value.
|
||||
//
|
||||
// These wrappers have no meaningful use within repeated fields as they lack
|
||||
// the ability to detect presence on individual elements.
|
||||
// These wrappers have no meaningful use within a map or a oneof since
|
||||
// individual entries of a map or fields of a oneof can already detect presence.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/wrapperspb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "WrappersProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// Wrapper message for `double`.
|
||||
//
|
||||
// The JSON representation for `DoubleValue` is JSON number.
|
||||
message DoubleValue {
|
||||
// The double value.
|
||||
double value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `float`.
|
||||
//
|
||||
// The JSON representation for `FloatValue` is JSON number.
|
||||
message FloatValue {
|
||||
// The float value.
|
||||
float value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `int64`.
|
||||
//
|
||||
// The JSON representation for `Int64Value` is JSON string.
|
||||
message Int64Value {
|
||||
// The int64 value.
|
||||
int64 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `uint64`.
|
||||
//
|
||||
// The JSON representation for `UInt64Value` is JSON string.
|
||||
message UInt64Value {
|
||||
// The uint64 value.
|
||||
uint64 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `int32`.
|
||||
//
|
||||
// The JSON representation for `Int32Value` is JSON number.
|
||||
message Int32Value {
|
||||
// The int32 value.
|
||||
int32 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `uint32`.
|
||||
//
|
||||
// The JSON representation for `UInt32Value` is JSON number.
|
||||
message UInt32Value {
|
||||
// The uint32 value.
|
||||
uint32 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `bool`.
|
||||
//
|
||||
// The JSON representation for `BoolValue` is JSON `true` and `false`.
|
||||
message BoolValue {
|
||||
// The bool value.
|
||||
bool value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `string`.
|
||||
//
|
||||
// The JSON representation for `StringValue` is JSON string.
|
||||
message StringValue {
|
||||
// The string value.
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `bytes`.
|
||||
//
|
||||
// The JSON representation for `BytesValue` is JSON string.
|
||||
message BytesValue {
|
||||
// The bytes value.
|
||||
bytes value = 1;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
Protocol Buffers - Google's data interchange format
|
||||
Copyright 2008 Google Inc.
|
||||
https://developers.google.com/protocol-buffers/
|
||||
|
||||
This package contains a precompiled binary version of the protocol buffer
|
||||
compiler (protoc). This binary is intended for users who want to use Protocol
|
||||
Buffers in languages other than C++ but do not want to compile protoc
|
||||
themselves. To install, simply place this binary somewhere in your PATH.
|
||||
|
||||
If you intend to use the included well known types then don't forget to
|
||||
copy the contents of the 'include' directory somewhere as well, for example
|
||||
into '/usr/local/include/'.
|
||||
|
||||
Please refer to our official github site for more installation instructions:
|
||||
https://github.com/protocolbuffers/protobuf
|
||||
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "app/service/main/game_mgr"
|
||||
|
||||
func main() {
|
||||
err := game_mgr.NewGameMgr().Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"app/service/main/message/pb"
|
||||
"app/service/main/msg_util"
|
||||
"app/service/robot/user"
|
||||
"core/network"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := network.NewTcpClient(
|
||||
":8888",
|
||||
newParser,
|
||||
newHandler)
|
||||
err := client.Connect(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = client.SendMsg(&pb.Report{
|
||||
Info: []*pb.ReportInfo{
|
||||
{
|
||||
OpenId: "1",
|
||||
Score: 123,
|
||||
},
|
||||
{
|
||||
OpenId: "2",
|
||||
Score: 456,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func newParser() network.ICodec {
|
||||
return msg_util.NewProtoCodec(msg_util.NewProtoParser("message", "MSG_TYPE"), 1024*64, false)
|
||||
}
|
||||
|
||||
func newHandler() network.INetHandler {
|
||||
return user.NewUser()
|
||||
}
|
||||
@ -1,167 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"app/internal/config"
|
||||
"app/servers/gate"
|
||||
"app/servers/robot"
|
||||
"app/servers/role"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"app/internal/flags"
|
||||
"app/internal/iniconfig"
|
||||
"app/internal/service"
|
||||
"app/servers/game"
|
||||
"app/servers/login"
|
||||
"core/abtime"
|
||||
"core/actor"
|
||||
"core/actor/cluster/mesh_provider/etcd"
|
||||
"core/actor/cluster/remote_provider/nats"
|
||||
"core/actor/cluster/remote_provider/prs"
|
||||
"core/goroutine"
|
||||
"core/log"
|
||||
"core/prometheus"
|
||||
"core/tools"
|
||||
)
|
||||
|
||||
var opts struct {
|
||||
Conf string `long:"conf" required:"true" description:"ini file path"`
|
||||
AppType string `long:"app" required:"true" choice:"game" choice:"chat" choice:"login" choice:"payment" choice:"webconsole" choice:"battle" choice:"robot" choice:"dbupdate" choice:"all" description:"app type"`
|
||||
AppId int32 `long:"id" required:"true" description:"app id"`
|
||||
LogFile string `long:"lfile" description:"Log file, the default output is stdout"`
|
||||
LogLevel string `long:"llevel" default:"debug" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" description:"Log level"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
flags.Parse(&opts)
|
||||
log.Init(opts.LogFile, opts.LogLevel)
|
||||
defer log.Stop()
|
||||
|
||||
freeOSMemory()
|
||||
goroutine.Try(func() {
|
||||
rand.Seed(abtime.Now().UnixNano()) //设置随机数种子
|
||||
|
||||
tools.PProfInit()
|
||||
iniconfig.Init(opts.Conf) //服务器基础配置加载
|
||||
tools.InitSnowflake(int64(opts.AppId))
|
||||
|
||||
systemConf := iniconfig.NewAppConf(opts.AppType, opts.AppId)
|
||||
system := initActorSystem(opts.AppType, opts.AppId, systemConf)
|
||||
|
||||
//策划配置档加载
|
||||
tools.AssertNil(config.Reload(systemConf.String("csv_dir")))
|
||||
system.Actor().RegistCmd("cfg_reload", func(param string) ([]byte, error) {
|
||||
err := config.Reload(systemConf.String("csv_dir"))
|
||||
return []byte("cfg_reload"), err
|
||||
})
|
||||
|
||||
switch opts.AppType {
|
||||
case service.All:
|
||||
newActor(system, service.Login, 1)
|
||||
newActor(system, service.Gate, 1)
|
||||
newActor(system, service.Gate, 2)
|
||||
newActor(system, service.Game, 1)
|
||||
newActor(system, service.GameMap, 1)
|
||||
newActor(system, service.RoleGate, 1)
|
||||
newActor(system, service.Role, 1)
|
||||
newActor(system, service.Role, 2)
|
||||
default:
|
||||
newActor(system, opts.AppType, opts.AppId)
|
||||
}
|
||||
|
||||
system.WaitStop()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func newActor(system *actor.ActorSystem, appType string, appId int32) {
|
||||
s := newService(appType, appId)
|
||||
tools.AssertNotNil(s)
|
||||
serviceId := service.ServiceId(appType, appId)
|
||||
system.NewActor(appType, serviceId, s, actorTimerAccuracy(appType), actorSetInitErrExit(appType))
|
||||
}
|
||||
|
||||
func newService(appType string, appId int32) (ret actor.IActorHandler) {
|
||||
switch appType {
|
||||
case service.Login:
|
||||
ret = login.NewLogin(appId)
|
||||
case service.Gate:
|
||||
ret = gate.NewGate(appId)
|
||||
case service.Game:
|
||||
ret = game.NewGame(appId)
|
||||
case service.Role:
|
||||
ret = role.NewRole(appId)
|
||||
case service.Robot:
|
||||
ret = robot.NewRobot(appId)
|
||||
default:
|
||||
log.KV("appType", appType).Error("invalid appType")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 设置定时器精度
|
||||
func actorTimerAccuracy(appType string) actor.ActorOption {
|
||||
switch appType {
|
||||
case service.Game, service.GameMap:
|
||||
return actor.SetTimerAccuracy(time.Second/20, time.Hour*24)
|
||||
case service.Role:
|
||||
return actor.SetTimerAccuracy(time.Second, time.Hour*24)
|
||||
case service.Robot:
|
||||
return actor.SetTimerAccuracy(time.Second/20, time.Hour*24)
|
||||
default:
|
||||
return actor.NilActorOption()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置Init失败是否退出system
|
||||
func actorSetInitErrExit(appType string) actor.ActorOption {
|
||||
//目前只有robot不退出
|
||||
switch appType {
|
||||
case service.Robot:
|
||||
return actor.NilActorOption()
|
||||
default:
|
||||
return actor.SetInitErrExit()
|
||||
}
|
||||
}
|
||||
|
||||
func initActorSystem(appType string, appId int32, conf *iniconfig.Config) *actor.ActorSystem {
|
||||
ops := []actor.SystemOption{}
|
||||
|
||||
if nats_addr := conf.MustString("nats_addr", ""); nats_addr != "" {
|
||||
ops = append(ops, actor.WithRemote(nats.NewRemote(nats_addr, fmt.Sprintf("%v%v", appType, appId))))
|
||||
} else if actor_addr := conf.MustString("actor_addr", ""); actor_addr != "" {
|
||||
ops = append(ops, actor.WithRemote(prs.NewRemote(actor_addr)))
|
||||
}
|
||||
|
||||
if etcd_addr := conf.MustString("etcd_addr", ""); etcd_addr != "" {
|
||||
ops = append(ops, actor.WithMesh(etcd.NewMesh(etcd_addr, conf.String("etcd_prefix"))))
|
||||
}
|
||||
|
||||
if prometheus_addr := conf.MustString("prometheus_addr", ""); prometheus_addr != "" {
|
||||
prom := prometheus.Default().Start(prometheus_addr)
|
||||
ops = append(ops, actor.WithPrometheus(prom))
|
||||
}
|
||||
|
||||
if ipcDir := conf.MustString("ipc_dir", "./tmp/prs/socks/"); len(ipcDir) > 0 {
|
||||
err := os.MkdirAll(ipcDir, os.ModePerm)
|
||||
tools.AssertNil(err)
|
||||
ipcFilename := path.Join(ipcDir, fmt.Sprintf("%v_%v.sock", appType, appId))
|
||||
ops = append(ops, actor.WithCMD(ipcFilename))
|
||||
}
|
||||
|
||||
ops = append(ops, actor.WithStopSignal())
|
||||
return actor.NewActorSystem(ops...)
|
||||
}
|
||||
|
||||
func freeOSMemory() {
|
||||
goroutine.GoLogic(func() {
|
||||
ticker := time.NewTicker(time.Minute * 10)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
}, nil)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +0,0 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"core/tools"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Parse(opts interface{}) {
|
||||
_, err := flags.NewParser(opts, flags.HelpFlag|flags.PrintErrors|flags.IgnoreUnknown).Parse()
|
||||
if ferr, ok := err.(*flags.Error); ok && ferr.Type == flags.ErrHelp {
|
||||
os.Exit(0)
|
||||
}
|
||||
tools.AssertNil(err)
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
package iniconfig
|
||||
|
||||
import (
|
||||
"core/tools"
|
||||
"fmt"
|
||||
"github.com/go-ini/ini"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var base *ini.Section
|
||||
var iniFile *ini.File
|
||||
var loadOnce sync.Once
|
||||
|
||||
func Init(filePath string) {
|
||||
loadOnce.Do(func() {
|
||||
file, err := ini.Load(filePath)
|
||||
tools.AssertNil(err)
|
||||
|
||||
file.BlockMode = false
|
||||
base, err = file.GetSection("base")
|
||||
tools.AssertNil(err)
|
||||
|
||||
iniFile = file
|
||||
})
|
||||
}
|
||||
|
||||
func NewAppConf(appType string, appId int32) *Config {
|
||||
conf := &Config{appType: appType, appId: appId}
|
||||
app, err := iniFile.GetSection(fmt.Sprintf("%s_%d", appType, appId))
|
||||
tools.AssertNil(err)
|
||||
conf.app = app
|
||||
return conf
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
appType string
|
||||
appId int32
|
||||
app *ini.Section
|
||||
}
|
||||
|
||||
// func (c *Config) AppId() int32 { return c.appId }
|
||||
// func (c *Config) AppType() string { return c.appType }
|
||||
func (c *Config) Has(key string) bool { return c.app.HasKey(key) || base.HasKey(key) }
|
||||
|
||||
func (c *Config) Int32(key string) int32 {
|
||||
value, err := c.findKey(key).Int()
|
||||
tools.AssertNil(err)
|
||||
return int32(value)
|
||||
}
|
||||
|
||||
func (c *Config) MustInt32(key string, val int32) int32 {
|
||||
if c.Has(key) {
|
||||
value, err := c.findKey(key).Int()
|
||||
if err == nil {
|
||||
return int32(value)
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (c *Config) Int64(key string) int64 {
|
||||
value, err := c.findKey(key).Int()
|
||||
tools.AssertNil(err)
|
||||
return int64(value)
|
||||
}
|
||||
|
||||
func (c *Config) MustInt64(key string, val int64) int64 {
|
||||
if c.Has(key) {
|
||||
value, err := c.findKey(key).Int()
|
||||
if err == nil {
|
||||
return int64(value)
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (c *Config) String(key string) string {
|
||||
return c.findKey(key).String()
|
||||
}
|
||||
|
||||
func (c *Config) MustString(key string, val string) string {
|
||||
if c.Has(key) {
|
||||
return c.findKey(key).String()
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (c *Config) Bool(key string) bool {
|
||||
value, err := c.findKey(key).Bool()
|
||||
tools.AssertNil(err)
|
||||
return value
|
||||
}
|
||||
|
||||
func (c *Config) MustBool(key string, val bool) bool {
|
||||
if c.Has(key) {
|
||||
value, err := c.findKey(key).Bool()
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 不含base
|
||||
func (c *Config) AppKeys() []string {
|
||||
return c.app.KeyStrings()
|
||||
}
|
||||
|
||||
func (c *Config) BaseKeys() []string {
|
||||
return base.KeyStrings()
|
||||
}
|
||||
|
||||
func (c *Config) ChildSections() []*ini.Section {
|
||||
return c.app.ChildSections()
|
||||
}
|
||||
|
||||
// app的配置可覆盖base
|
||||
func (c *Config) findKey(key string) *ini.Key {
|
||||
if c.app.HasKey(key) {
|
||||
return c.app.Key(key)
|
||||
}
|
||||
if base.HasKey(key) {
|
||||
return base.Key(key)
|
||||
}
|
||||
tools.AssertTrue(false, key)
|
||||
return nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,326 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// source: msgtype.proto
|
||||
|
||||
package message
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
import proto "google.golang.org/protobuf/proto"
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
//协议分段
|
||||
//1-999 common
|
||||
//1001-1999 role
|
||||
//2001-2999 game
|
||||
//3001-3999 map
|
||||
//4001-4999 league
|
||||
//5001-5999 chat
|
||||
//6001-6999 activity
|
||||
//50000+ result使用
|
||||
type MSG_TYPE int32
|
||||
|
||||
const (
|
||||
//占位
|
||||
MSG_TYPE__ERROR MSG_TYPE = 0 //Error
|
||||
MSG_TYPE__MessageResult MSG_TYPE = 1 //MessageResult
|
||||
MSG_TYPE__Login MSG_TYPE = 2 //Login
|
||||
MSG_TYPE__NotifyKickOut MSG_TYPE = 11 //NotifyKickOut
|
||||
MSG_TYPE__Ping MSG_TYPE = 21 //Ping
|
||||
MSG_TYPE__Pong MSG_TYPE = 22 //Pong
|
||||
MSG_TYPE__MapEntityMove MSG_TYPE = 3001 //MapEntityMove
|
||||
MSG_TYPE__MapEntityMoveTo MSG_TYPE = 3002 //MapEntityMoveTo
|
||||
MSG_TYPE__MapEntityStop MSG_TYPE = 3003 //MapEntityStop
|
||||
MSG_TYPE__MapEntityReturn MSG_TYPE = 3004 //MapEntityReturn
|
||||
MSG_TYPE__MapLookAt MSG_TYPE = 3010 //MapLookAt
|
||||
MSG_TYPE__MapRemoveLookAt MSG_TYPE = 3011 //MapRemoveLookAt
|
||||
MSG_TYPE__NotifyMapEntityList MSG_TYPE = 3101 //NotifyMapEntityList
|
||||
MSG_TYPE__NotifyMapBattleInfo MSG_TYPE = 3102 //NotifyMapBattleInfo
|
||||
MSG_TYPE__NotifyMapMoveInfo MSG_TYPE = 3103 //NotifyMapMoveInfo
|
||||
MSG_TYPE__NotifyMapHpInfo MSG_TYPE = 3104 //NotifyMapHpInfo
|
||||
MSG_TYPE__TestCreateMapEntity MSG_TYPE = 3999 //TestCreateMapEntity
|
||||
)
|
||||
|
||||
// Enum value maps for MSG_TYPE.
|
||||
var (
|
||||
MSG_TYPE_name = map[int32]string{
|
||||
0: "_ERROR",
|
||||
1: "_MessageResult",
|
||||
2: "_Login",
|
||||
11: "_NotifyKickOut",
|
||||
21: "_Ping",
|
||||
22: "_Pong",
|
||||
3001: "_MapEntityMove",
|
||||
3002: "_MapEntityMoveTo",
|
||||
3003: "_MapEntityStop",
|
||||
3004: "_MapEntityReturn",
|
||||
3010: "_MapLookAt",
|
||||
3011: "_MapRemoveLookAt",
|
||||
3101: "_NotifyMapEntityList",
|
||||
3102: "_NotifyMapBattleInfo",
|
||||
3103: "_NotifyMapMoveInfo",
|
||||
3104: "_NotifyMapHpInfo",
|
||||
3999: "_TestCreateMapEntity",
|
||||
}
|
||||
MSG_TYPE_value = map[string]int32{
|
||||
"_ERROR": 0,
|
||||
"_MessageResult": 1,
|
||||
"_Login": 2,
|
||||
"_NotifyKickOut": 11,
|
||||
"_Ping": 21,
|
||||
"_Pong": 22,
|
||||
"_MapEntityMove": 3001,
|
||||
"_MapEntityMoveTo": 3002,
|
||||
"_MapEntityStop": 3003,
|
||||
"_MapEntityReturn": 3004,
|
||||
"_MapLookAt": 3010,
|
||||
"_MapRemoveLookAt": 3011,
|
||||
"_NotifyMapEntityList": 3101,
|
||||
"_NotifyMapBattleInfo": 3102,
|
||||
"_NotifyMapMoveInfo": 3103,
|
||||
"_NotifyMapHpInfo": 3104,
|
||||
"_TestCreateMapEntity": 3999,
|
||||
}
|
||||
)
|
||||
|
||||
func (x MSG_TYPE) Enum() *MSG_TYPE {
|
||||
p := new(MSG_TYPE)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x MSG_TYPE) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (MSG_TYPE) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgtype_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (MSG_TYPE) Type() protoreflect.EnumType {
|
||||
return &file_msgtype_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x MSG_TYPE) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MSG_TYPE.Descriptor instead.
|
||||
func (MSG_TYPE) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type MSG_RESULT int32
|
||||
|
||||
const (
|
||||
MSG_RESULT_SUCCESS MSG_RESULT = 0 //执行成功
|
||||
MSG_RESULT_FAILED MSG_RESULT = 1 //协议执行失败,原因模糊
|
||||
MSG_RESULT_BAD_POS MSG_RESULT = 2 //非法坐标
|
||||
MSG_RESULT_USER_OFFLINE MSG_RESULT = 3 //玩家已离线
|
||||
)
|
||||
|
||||
// Enum value maps for MSG_RESULT.
|
||||
var (
|
||||
MSG_RESULT_name = map[int32]string{
|
||||
0: "SUCCESS",
|
||||
1: "FAILED",
|
||||
2: "BAD_POS",
|
||||
3: "USER_OFFLINE",
|
||||
}
|
||||
MSG_RESULT_value = map[string]int32{
|
||||
"SUCCESS": 0,
|
||||
"FAILED": 1,
|
||||
"BAD_POS": 2,
|
||||
"USER_OFFLINE": 3,
|
||||
}
|
||||
)
|
||||
|
||||
func (x MSG_RESULT) Enum() *MSG_RESULT {
|
||||
p := new(MSG_RESULT)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x MSG_RESULT) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (MSG_RESULT) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgtype_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (MSG_RESULT) Type() protoreflect.EnumType {
|
||||
return &file_msgtype_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x MSG_RESULT) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MSG_RESULT.Descriptor instead.
|
||||
func (MSG_RESULT) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *Error) Reset() {
|
||||
*x = Error{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_msgtype_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Error) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (x *Error) FromDB(data []byte) error {
|
||||
return proto.Unmarshal(data, x)
|
||||
}
|
||||
|
||||
func (x *Error) ToDB() ([]byte, error) {
|
||||
return proto.Marshal(x)
|
||||
}
|
||||
|
||||
func (*Error) ProtoMessage() {}
|
||||
|
||||
func (x *Error) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgtype_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Error.ProtoReflect.Descriptor instead.
|
||||
func (*Error) Descriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_msgtype_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_msgtype_proto_rawDesc = []byte{
|
||||
0x0a, 0x0d, 0x6d, 0x73, 0x67, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x2a, 0xe1, 0x02, 0x0a, 0x08, 0x4d, 0x53, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x5f, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x10, 0x01, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x5f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x5f, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x79, 0x4b, 0x69, 0x63, 0x6b, 0x4f, 0x75, 0x74, 0x10, 0x0b, 0x12, 0x09,
|
||||
0x0a, 0x05, 0x5f, 0x50, 0x69, 0x6e, 0x67, 0x10, 0x15, 0x12, 0x09, 0x0a, 0x05, 0x5f, 0x50, 0x6f,
|
||||
0x6e, 0x67, 0x10, 0x16, 0x12, 0x13, 0x0a, 0x0e, 0x5f, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x69,
|
||||
0x74, 0x79, 0x4d, 0x6f, 0x76, 0x65, 0x10, 0xb9, 0x17, 0x12, 0x15, 0x0a, 0x10, 0x5f, 0x4d, 0x61,
|
||||
0x70, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x10, 0xba, 0x17,
|
||||
0x12, 0x13, 0x0a, 0x0e, 0x5f, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74,
|
||||
0x6f, 0x70, 0x10, 0xbb, 0x17, 0x12, 0x15, 0x0a, 0x10, 0x5f, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74,
|
||||
0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x10, 0xbc, 0x17, 0x12, 0x0f, 0x0a, 0x0a,
|
||||
0x5f, 0x4d, 0x61, 0x70, 0x4c, 0x6f, 0x6f, 0x6b, 0x41, 0x74, 0x10, 0xc2, 0x17, 0x12, 0x15, 0x0a,
|
||||
0x10, 0x5f, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x6f, 0x6b, 0x41,
|
||||
0x74, 0x10, 0xc3, 0x17, 0x12, 0x19, 0x0a, 0x14, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d,
|
||||
0x61, 0x70, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x10, 0x9d, 0x18, 0x12,
|
||||
0x19, 0x0a, 0x14, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x61, 0x70, 0x42, 0x61, 0x74,
|
||||
0x74, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x10, 0x9e, 0x18, 0x12, 0x17, 0x0a, 0x12, 0x5f, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x61, 0x70, 0x4d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x10, 0x9f, 0x18, 0x12, 0x15, 0x0a, 0x10, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x61,
|
||||
0x70, 0x48, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x10, 0xa0, 0x18, 0x12, 0x19, 0x0a, 0x14, 0x5f, 0x54,
|
||||
0x65, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x69,
|
||||
0x74, 0x79, 0x10, 0x9f, 0x1f, 0x2a, 0x44, 0x0a, 0x0a, 0x4d, 0x53, 0x47, 0x5f, 0x52, 0x45, 0x53,
|
||||
0x55, 0x4c, 0x54, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07,
|
||||
0x42, 0x41, 0x44, 0x5f, 0x50, 0x4f, 0x53, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x53, 0x45,
|
||||
0x52, 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x03, 0x42, 0x28, 0x5a, 0x26, 0x67,
|
||||
0x6f, 0x61, 0x74, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x73,
|
||||
0x2d, 0x61, 0x70, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_msgtype_proto_rawDescOnce sync.Once
|
||||
file_msgtype_proto_rawDescData = file_msgtype_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_msgtype_proto_rawDescGZIP() []byte {
|
||||
file_msgtype_proto_rawDescOnce.Do(func() {
|
||||
file_msgtype_proto_rawDescData = protoimpl.X.CompressGZIP(file_msgtype_proto_rawDescData)
|
||||
})
|
||||
return file_msgtype_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_msgtype_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_msgtype_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_msgtype_proto_goTypes = []interface{}{
|
||||
(MSG_TYPE)(0), // 0: message.MSG_TYPE
|
||||
(MSG_RESULT)(0), // 1: message.MSG_RESULT
|
||||
(*Error)(nil), // 2: message.Error
|
||||
}
|
||||
var file_msgtype_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_msgtype_proto_init() }
|
||||
func file_msgtype_proto_init() {
|
||||
if File_msgtype_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_msgtype_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Error); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_msgtype_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_msgtype_proto_goTypes,
|
||||
DependencyIndexes: file_msgtype_proto_depIdxs,
|
||||
EnumInfos: file_msgtype_proto_enumTypes,
|
||||
MessageInfos: file_msgtype_proto_msgTypes,
|
||||
}.Build()
|
||||
File_msgtype_proto = out.File
|
||||
file_msgtype_proto_rawDesc = nil
|
||||
file_msgtype_proto_goTypes = nil
|
||||
file_msgtype_proto_depIdxs = nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
||||
package msg_util
|
||||
|
||||
import (
|
||||
"core/actor/actor_msg"
|
||||
"core/tools"
|
||||
)
|
||||
|
||||
/*
|
||||
按消息/请求的数据类型注册回调
|
||||
注意:不是区分具体类型的值
|
||||
*/
|
||||
|
||||
func NewMsgTypeHandler() *MsgTypeHandler {
|
||||
return &MsgTypeHandler{msgMap: make(map[string]MsgFun), reqMap: make(map[string]ReqFun)}
|
||||
}
|
||||
|
||||
type MsgFun func(sourceId, msg interface{})
|
||||
type ReqFun func(requestId, msg interface{})
|
||||
|
||||
type MsgTypeHandler struct {
|
||||
msgMap map[string]MsgFun
|
||||
reqMap map[string]ReqFun
|
||||
}
|
||||
|
||||
// 注册消息回调
|
||||
func (h *MsgTypeHandler) RegistMsg(msg interface{}, f MsgFun) {
|
||||
msgName := MsgName(msg)
|
||||
_, ok := h.msgMap[msgName]
|
||||
tools.AssertTrue(!ok, "regist repeated msg=%v", msgName)
|
||||
h.msgMap[msgName] = f
|
||||
}
|
||||
|
||||
func (h *MsgTypeHandler) HandleMsg(sourceId, msg interface{}) bool {
|
||||
msgName := MsgName(msg)
|
||||
handler := h.msgMap[msgName]
|
||||
tools.AssertTrue(handler != nil, "msg=%v not regist handler", msgName)
|
||||
handler(sourceId, msg)
|
||||
return true
|
||||
}
|
||||
|
||||
// 注册请求回调
|
||||
func (h *MsgTypeHandler) RegistReq(msg interface{}, f ReqFun) {
|
||||
msgName := MsgName(msg)
|
||||
_, ok := h.reqMap[msgName]
|
||||
tools.AssertTrue(!ok, "regist repeated req=%v", msgName)
|
||||
h.reqMap[msgName] = f
|
||||
}
|
||||
|
||||
func (h *MsgTypeHandler) HandleReq(requestId, msg interface{}) {
|
||||
msgName := MsgName(msg)
|
||||
handler := h.reqMap[msgName]
|
||||
tools.AssertTrue(handler != nil, "req=%v not regist handler", msgName)
|
||||
//log.KV("msg", msgName).KV("requestId", requestId).Debug("hand request")
|
||||
handler(requestId, msg)
|
||||
}
|
||||
|
||||
func MsgName(msg interface{}) string { return actor_msg.MsgName(msg) }
|
||||
@ -1,52 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
Login = "login"
|
||||
Gate = "gate"
|
||||
|
||||
RoleGate = "rolegate"
|
||||
LeagueGate = "leaguegate"
|
||||
|
||||
Game = "game"
|
||||
|
||||
GameMap = "gamemap"
|
||||
|
||||
Role = "role"
|
||||
League = "league"
|
||||
|
||||
Chat = "chat"
|
||||
Webconsole = "webconsole"
|
||||
Payment = "payment"
|
||||
|
||||
//工具
|
||||
All = "all" //测试
|
||||
Robot = "robot"
|
||||
DBUpdate = "dbupdate"
|
||||
)
|
||||
|
||||
func LoginId(id int32) string { return ServiceId(Login, id) }
|
||||
func GateId(id int32) string { return ServiceId(Gate, id) }
|
||||
func GameId(id int32) string { return ServiceId(Game, id) }
|
||||
func GameMapId(id int32) string { return ServiceId(GameMap, id) }
|
||||
func RoleGateId(id int32) string { return ServiceId(RoleGate, id) }
|
||||
func RoleId(id int32) string { return ServiceId(Role, id) }
|
||||
|
||||
func ChatId(id int32) string { return ServiceId(Chat, id) }
|
||||
func WebconsoleId(id int32) string { return ServiceId(Webconsole, id) }
|
||||
func PaymentId(id int32) string { return ServiceId(Payment, id) }
|
||||
|
||||
func RobotId(id int32) string { return ServiceId(Robot, id) }
|
||||
func DBUpdateId(id int32) string { return ServiceId(DBUpdate, id) }
|
||||
func ServiceId(tp string, id int32) string { return fmt.Sprintf("%s_%d", tp, id) }
|
||||
|
||||
type GameServerStatus int32
|
||||
|
||||
const (
|
||||
StatusClose GameServerStatus = iota //未开放
|
||||
StatusMaintain //维护
|
||||
StatusOpen //开启
|
||||
)
|
||||
@ -1,13 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/internal/service_base"
|
||||
)
|
||||
|
||||
type IEntity interface {
|
||||
service_base.ITimerManager
|
||||
IGameSub
|
||||
|
||||
RID() int64
|
||||
Type() int32
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/internal/service_base"
|
||||
"core/dispatcher"
|
||||
"core/ormdb"
|
||||
)
|
||||
|
||||
type IGame interface {
|
||||
service_base.IServiceBase
|
||||
}
|
||||
|
||||
type IGameSub interface {
|
||||
Game() IGame
|
||||
DBSaver() ormdb.IQueSaver
|
||||
GameDispatcher() dispatcher.IDispatcher
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package gate
|
||||
|
||||
import (
|
||||
"app/internal/msg_inner"
|
||||
"app/servers/gate/logic/fathers"
|
||||
)
|
||||
|
||||
func (s *Gate) initAPI() {
|
||||
s.RegistMsg((*fathers.SessionCreate)(nil), s.onlineMgr.OnConnect)
|
||||
s.RegistMsg((*fathers.SessionClose)(nil), s.onlineMgr.OnDisconnect)
|
||||
s.RegistMsg((*fathers.SessionMsg)(nil), s.onlineMgr.OnMessage)
|
||||
|
||||
s.RegistMsg((*msg_inner.Send2VirtualUser)(nil), s.onlineMgr.OnMessage2User)
|
||||
s.RegistMsg((*msg_inner.BroadCast2VirtualUser)(nil), s.onlineMgr.OnBroadCastMessage2User)
|
||||
s.RegistMsg((*msg_inner.GroupCast2VirtualUser)(nil), s.onlineMgr.OnGroupCast2VirtualUser)
|
||||
s.RegistMsg((*msg_inner.UserLoginBroadcastGate)(nil), s.onlineMgr.OnUserLoginBroadcastGate)
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/internal/service_base"
|
||||
)
|
||||
|
||||
type IGate interface {
|
||||
service_base.IServiceBase
|
||||
UserMgr() IGateUserManager
|
||||
UserByRID(rid int64) IGateUser
|
||||
BroadcastAll(msg interface{})
|
||||
BroadcastGate(msg interface{})
|
||||
}
|
||||
|
||||
type IGateSub interface {
|
||||
Gate() IGate
|
||||
}
|
||||
|
||||
func NewGateSub(gate IGate) IGateSub {
|
||||
return &GateSub{gate: gate}
|
||||
}
|
||||
|
||||
type GateSub struct {
|
||||
gate IGate
|
||||
}
|
||||
|
||||
func (this *GateSub) Gate() IGate { return this.gate }
|
||||
@ -1,20 +0,0 @@
|
||||
package fathers
|
||||
|
||||
type IGateUser interface {
|
||||
RID() int64
|
||||
UID() int64
|
||||
SID() int32
|
||||
}
|
||||
|
||||
type IGateUserModule interface {
|
||||
SetUser(IGateUser)
|
||||
OnInit() error
|
||||
}
|
||||
|
||||
type ModuleBase struct {
|
||||
IGateUser
|
||||
}
|
||||
|
||||
func (this *ModuleBase) SetUser(user IGateUser) { this.IGateUser = user }
|
||||
func (this *ModuleBase) OnInit() error { return nil }
|
||||
func (this *ModuleBase) OnNewUser() error { return nil }
|
||||
@ -1,42 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"core/network"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type IOnlineManager interface {
|
||||
IGateSub
|
||||
OnConnect(sourceId, msg interface{})
|
||||
OnDisconnect(sourceId, msg interface{})
|
||||
RemoteIP(rid int64) string
|
||||
|
||||
OnMessage(sourceId, msg interface{})
|
||||
SendMsg(rid int64, msg proto.Message)
|
||||
Broadcast(msg proto.Message)
|
||||
|
||||
IsOnline(rid int64) bool
|
||||
OnlineNum() int
|
||||
GetOnlineAll() []int64
|
||||
}
|
||||
|
||||
type IGateUserSession interface {
|
||||
network.INetSession
|
||||
SetRID(rid int64)
|
||||
RID() int64
|
||||
SetSID(sid int32)
|
||||
SID() int32
|
||||
}
|
||||
|
||||
type SessionCreate struct {
|
||||
Session IGateUserSession
|
||||
}
|
||||
|
||||
type SessionClose struct {
|
||||
Session IGateUserSession
|
||||
}
|
||||
|
||||
type SessionMsg struct {
|
||||
Session IGateUserSession
|
||||
Msg proto.Message
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package fathers
|
||||
|
||||
type IGateUserManager interface {
|
||||
NewUser(uid int64, rid int64, sid int32) IGateUser
|
||||
Add(user IGateUser) (ok bool)
|
||||
Del(user IGateUser) (ok bool)
|
||||
|
||||
User(rid int64) IGateUser
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package gate_user
|
||||
|
||||
import (
|
||||
"app/servers/gate/logic/fathers"
|
||||
)
|
||||
|
||||
var _ fathers.IGateUser = (*GateUser)(nil) //interface实现检查
|
||||
type GateUser struct {
|
||||
fathers.IGateSub
|
||||
rid int64
|
||||
uid int64
|
||||
sid int32
|
||||
}
|
||||
|
||||
func NewGateUser(gateSub fathers.IGateSub, uid int64, rid int64, sid int32) *GateUser {
|
||||
user := &GateUser{
|
||||
IGateSub: gateSub,
|
||||
uid: uid,
|
||||
rid: rid,
|
||||
sid: sid,
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func (this *GateUser) RID() int64 { return this.rid }
|
||||
func (this *GateUser) UID() int64 { return this.uid }
|
||||
func (this *GateUser) SID() int32 { return this.sid }
|
||||
@ -1,64 +0,0 @@
|
||||
package mgr_online
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/servers/gate/logic/fathers"
|
||||
"core/abtime"
|
||||
"core/log"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (this *OnlineManager) handeLogin(sm *fathers.SessionMsg) {
|
||||
var recvData = sm.Msg.(*message.Login)
|
||||
rid := recvData.RID
|
||||
|
||||
log.KV("rid", rid).KV("ip", sm.Session.RemoteIP()).KV("msg", recvData).KV("msgip", recvData.IP).Info("gate handeLogin")
|
||||
recvData.IP = sm.Session.RemoteIP()
|
||||
|
||||
//TODO 临时屏蔽
|
||||
//if this.startAt > recvData.LoginTime || !app_tools.IsLogin(this.Gate().LoginKey(), recvData.SID, rid, recvData.UID, recvData.LoginTime, recvData.Mute, recvData.Ban, recvData.Super, recvData.Session) {
|
||||
// log.KV("start", this.startAt).KV("login", recvData.LoginTime).KV("rid", rid).Info("login check failed")
|
||||
// this.respLogin(sm.Session, message.MSG_RESULT_FAILED)
|
||||
// return
|
||||
//}
|
||||
|
||||
user := this.Gate().UserByRID(rid)
|
||||
if isNewUser := user == nil; isNewUser {
|
||||
user = this.Gate().UserMgr().NewUser(recvData.UID, rid, recvData.SID)
|
||||
if !this.Gate().UserMgr().Add(user) {
|
||||
log.KV("rid", rid).Warn("add user failed")
|
||||
this.respLogin(sm.Session, message.MSG_RESULT_FAILED)
|
||||
return
|
||||
}
|
||||
}
|
||||
if user != nil && this.IsOnline(rid) {
|
||||
log.KV("rid", rid).Info("replace login")
|
||||
this.SendMsg(rid, &message.NotifyKickOut{Reason: message.KICK_OUT_REASON_REPLACE})
|
||||
this.unbind(rid)
|
||||
}
|
||||
|
||||
if !this.bind(user.RID(), user.SID(), sm.Session) {
|
||||
log.KV("rid", user.RID()).Warn("bind user failed")
|
||||
this.respLogin(sm.Session, message.MSG_RESULT_FAILED)
|
||||
return
|
||||
}
|
||||
this.respLogin(sm.Session, message.MSG_RESULT_SUCCESS)
|
||||
|
||||
log.KV("uid", user.UID()).KV("rid", user.RID()).KV("ip", sm.Session.RemoteIP()).KV("login_session", recvData.Session).KV("session", sm.Session.Id()).Info("gate login success")
|
||||
}
|
||||
|
||||
func (this *OnlineManager) respLogin(session fathers.IGateUserSession, result message.MSG_RESULT) {
|
||||
msg := &message.LoginResult{
|
||||
Result: result,
|
||||
Role: session.RID(),
|
||||
ServerTime: abtime.Now().UnixNano(),
|
||||
ServerZone: int32(abtime.TimeZone / 3600),
|
||||
}
|
||||
respData, _ := proto.Marshal(msg)
|
||||
msgResult := &message.MessageResult{
|
||||
ProtoId: int32(message.MSG_TYPE__Login),
|
||||
Result: result,
|
||||
Data: respData,
|
||||
}
|
||||
session.SendMsg(msgResult)
|
||||
}
|
||||
@ -1,173 +0,0 @@
|
||||
package mgr_online
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/internal/msg_inner"
|
||||
"app/internal/msg_util"
|
||||
"app/servers/gate/logic/fathers"
|
||||
"core/abtime"
|
||||
"core/log"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func New(gate fathers.IGate) *OnlineManager {
|
||||
o := &OnlineManager{
|
||||
IGateSub: fathers.NewGateSub(gate),
|
||||
u2s: make(map[int64]fathers.IGateUserSession),
|
||||
startAt: abtime.Now().Unix(),
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
var _ fathers.IOnlineManager = (*OnlineManager)(nil) //interface实现检查
|
||||
type OnlineManager struct {
|
||||
fathers.IGateSub
|
||||
u2s map[int64]fathers.IGateUserSession //rid=>session
|
||||
startAt int64
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnConnect(sourceId, msg interface{}) {}
|
||||
func (this *OnlineManager) OnDisconnect(sourceId, msg interface{}) {
|
||||
session := msg.(*fathers.SessionClose).Session
|
||||
this.unbind(session.RID())
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnMessage(sourceId, msg interface{}) {
|
||||
data := msg.(*fathers.SessionMsg)
|
||||
msgName := msg_util.MsgName(data.Msg)
|
||||
defer this.Gate().Prometheus().RecordHandMsg(abtime.Now(), msgName)
|
||||
|
||||
if _, ok := data.Msg.(*message.Login); ok {
|
||||
this.handeLogin(data)
|
||||
} else {
|
||||
if user := this.Gate().UserByRID(data.Session.RID()); user != nil {
|
||||
this.handleMessage(user, data.Msg)
|
||||
} else {
|
||||
log.KV("rid", data.Session.RID()).KV("session", data.Session.Id()).KV("msg", msg_util.MsgName(msg)).KV("data", data.Msg).Warn("msg not find user")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnMessage2User(sourceId, msg interface{}) {
|
||||
data := msg.(*msg_inner.Send2VirtualUser)
|
||||
rid := data.RID
|
||||
if session, ok := this.u2s[rid]; ok {
|
||||
session.SendMsg(data.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnBroadCastMessage2User(sourceId, msg interface{}) {
|
||||
data := msg.(*msg_inner.BroadCast2VirtualUser)
|
||||
for _, session := range this.u2s {
|
||||
if user := this.User(session.RID()); user.SID() == data.SID {
|
||||
session.SendMsg(data.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
func (this *OnlineManager) OnGroupCast2VirtualUser(sourceId, msg interface{}) {
|
||||
data := msg.(*msg_inner.GroupCast2VirtualUser)
|
||||
for _, rid := range data.RIDList {
|
||||
if session, ok := this.u2s[rid]; ok {
|
||||
session.SendMsg(data.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnUserLoginBroadcastGate(sourceId, msg interface{}) {
|
||||
if sourceId == this.Gate().Actor().Id() {
|
||||
return
|
||||
}
|
||||
data := msg.(*msg_inner.UserLoginBroadcastGate)
|
||||
rid := data.RID
|
||||
this.SendMsg(rid, &message.NotifyKickOut{Reason: message.KICK_OUT_REASON_REPLACE})
|
||||
this.unbind(rid)
|
||||
}
|
||||
|
||||
func (this *OnlineManager) bind(rid int64, sid int32, session fathers.IGateUserSession) bool {
|
||||
if _, ok := this.u2s[rid]; ok {
|
||||
return false
|
||||
}
|
||||
this.u2s[rid] = session
|
||||
session.SetRID(rid)
|
||||
session.SetSID(sid)
|
||||
this.Gate().Prometheus().RecordOnline(len(this.u2s))
|
||||
req := &msg_inner.VirtualUserCreate{RID: rid, GID: this.Gate().SID()}
|
||||
this.Gate().BroadcastAll(req)
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *OnlineManager) unbind(rid int64) {
|
||||
session, ok := this.u2s[rid]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if user := this.User(rid); user != nil {
|
||||
//user.OnUserOffLine()
|
||||
}
|
||||
session.SetRID(0)
|
||||
session.SetSID(0)
|
||||
delete(this.u2s, rid)
|
||||
this.Gate().Prometheus().RecordOnline(len(this.u2s))
|
||||
req := &msg_inner.VirtualUserDestroy{RID: rid}
|
||||
this.Gate().BroadcastAll(req)
|
||||
}
|
||||
|
||||
func (this *OnlineManager) OnlineNum() int { return len(this.u2s) }
|
||||
func (this *OnlineManager) User(rid int64) fathers.IGateUser {
|
||||
if _, ok := this.u2s[rid]; !ok {
|
||||
return nil
|
||||
}
|
||||
return this.Gate().UserByRID(rid)
|
||||
}
|
||||
|
||||
func (this *OnlineManager) GetOnlineAll() []int64 {
|
||||
var ret []int64
|
||||
for rid := range this.u2s {
|
||||
ret = append(ret, rid)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// IsOnline 获取当前rid是否在线.
|
||||
func (this *OnlineManager) IsOnline(rid int64) bool {
|
||||
_, ok := this.u2s[rid]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (this *OnlineManager) SendMsg(rid int64, msg proto.Message) {
|
||||
if sess, ok := this.u2s[rid]; ok {
|
||||
sess.SendMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) Broadcast(msg proto.Message) {
|
||||
for _, sess := range this.u2s {
|
||||
sess.SendMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) Kick(rid int64, reason message.KICK_OUT_REASON, ban message.BAN_REASON) {
|
||||
session, ok := this.u2s[rid]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
session.SendMsg(&message.NotifyKickOut{Reason: reason, Ban: ban})
|
||||
this.unbind(rid)
|
||||
}
|
||||
|
||||
func (this *OnlineManager) NotifyClose() {
|
||||
for rid := range this.u2s {
|
||||
this.Kick(rid, message.KICK_OUT_REASON_MAINTAIN, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *OnlineManager) RemoteIP(rid int64) string {
|
||||
if sess, ok := this.u2s[rid]; ok {
|
||||
return sess.RemoteIP()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *OnlineManager) handleMessage(user fathers.IGateUser, msg proto.Message) {
|
||||
//msg_name := msg_util.MsgName(msg)
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package mgr_user
|
||||
|
||||
import (
|
||||
"app/servers/gate/logic/fathers"
|
||||
"app/servers/gate/logic/gate_user"
|
||||
"core/log"
|
||||
)
|
||||
|
||||
func NewGateUserMgr(gate fathers.IGate) *GateUserManager {
|
||||
u := &GateUserManager{
|
||||
IGateSub: fathers.NewGateSub(gate),
|
||||
users: make(map[int64]*gate_user.GateUser),
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// 玩家列表
|
||||
var _ fathers.IGateUserManager = (*GateUserManager)(nil) //interface实现检查
|
||||
type GateUserManager struct {
|
||||
fathers.IGateSub
|
||||
users map[int64]*gate_user.GateUser
|
||||
}
|
||||
|
||||
func (this *GateUserManager) Len() int32 {
|
||||
return int32(len(this.users))
|
||||
}
|
||||
|
||||
func (this *GateUserManager) Range(fn func(user fathers.IGateUser) (stop bool)) {
|
||||
for _, user := range this.users {
|
||||
if fn(user) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (this *GateUserManager) User(rid int64) fathers.IGateUser {
|
||||
entity := this.users[rid]
|
||||
if entity == nil {
|
||||
return nil
|
||||
}
|
||||
return entity
|
||||
}
|
||||
|
||||
func (this *GateUserManager) Add(entity fathers.IGateUser) (ok bool) {
|
||||
if this.users[entity.RID()] != nil {
|
||||
log.KV("rid", entity.RID()).Error("add entity already exists")
|
||||
return
|
||||
}
|
||||
this.users[entity.RID()] = entity.(*gate_user.GateUser)
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *GateUserManager) Del(user fathers.IGateUser) (ok bool) {
|
||||
if this.users[user.RID()] != nil {
|
||||
delete(this.users, user.RID())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *GateUserManager) NewUser(uid int64, rid int64, sid int32) fathers.IGateUser {
|
||||
user := gate_user.NewGateUser(this, uid, rid, sid)
|
||||
return user
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
package user_session
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/internal/msg_inner"
|
||||
"app/internal/service"
|
||||
"app/servers/gate/logic/fathers"
|
||||
"core/abtime"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
//协议分段
|
||||
//1-999 common
|
||||
//1001-1999 role
|
||||
//2001-2999 game
|
||||
//3001-3999 map
|
||||
//4001-4999 league
|
||||
//5001-5999 chat
|
||||
//6001-6999 activity
|
||||
|
||||
// 根据协议号进行转发
|
||||
func (s *UserSession) handeSessionMsg(msgId int32, rawData interface{}) {
|
||||
msgTarget := msgId / 1000
|
||||
|
||||
switch msgTarget {
|
||||
case 0: //gate
|
||||
s.handleByGate(msgId, rawData)
|
||||
case 3: //map
|
||||
s.sendUserMessage(service.GameMapId(s.SID()), msgId, rawData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *UserSession) handleByGate(msgId int32, rawData interface{}) {
|
||||
//注意这里不是主线程
|
||||
if data, ok := s.gate.Parser().Unmarshal(msgId, rawData.([]byte)); ok {
|
||||
switch msgId {
|
||||
case int32(message.MSG_TYPE__Ping):
|
||||
ping := data.(*message.Ping)
|
||||
s.SendMsg(&message.Pong{ServerTime: abtime.Now().UnixNano(), ServerZone: int32(abtime.TimeZone / 3600), ClientTime: ping.ClientTime})
|
||||
default:
|
||||
s.gate.Actor().Send(s.gate.Actor().Id(), &fathers.SessionMsg{Session: s, Msg: data.(proto.Message)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *UserSession) sendUserMessage(targetId interface{}, msgId int32, rawData interface{}) {
|
||||
userMsg := &msg_inner.VirtualUserMessage{
|
||||
RID: s.rid,
|
||||
MsgId: msgId,
|
||||
Data: rawData.([]byte),
|
||||
}
|
||||
s.gate.Actor().Send(targetId, userMsg)
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package user_session
|
||||
|
||||
import (
|
||||
"app/servers/gate/logic/fathers"
|
||||
"app/servers/internal/ip2country"
|
||||
"core/network"
|
||||
)
|
||||
|
||||
func NewUserSession(gate fathers.IGate) *UserSession {
|
||||
return &UserSession{gate: gate}
|
||||
}
|
||||
|
||||
type UserSession struct {
|
||||
network.BaseNetHandler
|
||||
gate fathers.IGate
|
||||
rid int64
|
||||
sid int32
|
||||
country string
|
||||
}
|
||||
|
||||
func (s *UserSession) OnSessionCreated() {
|
||||
s.country = ip2country.ToCountryISO(s.RemoteIP())
|
||||
s.gate.Actor().Send(s.gate.Actor().Id(), &fathers.SessionCreate{Session: s})
|
||||
}
|
||||
|
||||
func (s *UserSession) OnSessionClosed() {
|
||||
s.gate.Actor().Send(s.gate.Actor().Id(), &fathers.SessionClose{Session: s})
|
||||
}
|
||||
|
||||
func (s *UserSession) OnRecv(msgId int32, data interface{}) {
|
||||
s.handeSessionMsg(msgId, data)
|
||||
}
|
||||
|
||||
func (s *UserSession) SetRID(rid int64) { s.rid = rid }
|
||||
func (s *UserSession) RID() int64 { return s.rid }
|
||||
func (s *UserSession) SetSID(sid int32) { s.sid = sid }
|
||||
func (s *UserSession) SID() int32 { return s.sid }
|
||||
@ -1,81 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"core/abtime"
|
||||
"core/ormdb"
|
||||
"core/tools"
|
||||
"reflect"
|
||||
"time"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type IDBBase interface {
|
||||
ormdb.IQueSaver
|
||||
DBCount(ormdb.IDBObj, func(*xorm.Session) *xorm.Session) (int64, error)
|
||||
PageLoad(ormdb.IDBObj, func(*xorm.Session) *xorm.Session) (interface{}, error)
|
||||
LoadAll(ormdb.IDBObj, func(*xorm.Session) *xorm.Session) (interface{}, error)
|
||||
CreateTable(beans ...interface{}) error
|
||||
DBEngine() *xorm.Engine
|
||||
NewDBSession() (*xorm.Session, error)
|
||||
|
||||
setBase(datas interface{})
|
||||
}
|
||||
|
||||
var _ IDBBase = (*DBBase)(nil) //
|
||||
type DBBase struct {
|
||||
db *ormdb.MysqlEngine //数据库
|
||||
}
|
||||
|
||||
func (s *DBBase) Init(service *ServiceBase) {
|
||||
mysql_dsn := service.Config().MustString("mysql", "")
|
||||
if mysql_dsn == "" {
|
||||
return
|
||||
}
|
||||
flushInterval := time.Second * time.Duration(service.Config().MustInt32("db_flush", 1))
|
||||
dbPageSize := service.Config().MustInt64("db_page_size", 200000)
|
||||
dbQueNum := service.Config().MustInt64("db_que_num", 4)
|
||||
var err error
|
||||
s.db, err = ormdb.New(mysql_dsn, ormdb.WithFlushInterval(flushInterval), ormdb.WithPrometheus(service.Actor().Prometheus()), ormdb.WithPageSize(dbPageSize), ormdb.WithQueNum(dbQueNum))
|
||||
tools.AssertNil(err)
|
||||
service.AddScheduleTask(abtime.Now(), flushInterval, func(dt int64) { s.db.Flush(false) })
|
||||
}
|
||||
|
||||
func (s *DBBase) DBEngine() *xorm.Engine { return s.db.Engine() }
|
||||
func (s *DBBase) NewDBSession() (*xorm.Session, error) { return s.db.NewSession() }
|
||||
func (s *DBBase) CreateTable(beans ...interface{}) error { return s.db.CreateTable(beans...) }
|
||||
func (s *DBBase) TableName(bean interface{}) string { return s.db.TableName(bean) }
|
||||
func (s *DBBase) AddToQue(data ormdb.IDBObj) { s.db.AddToQue(data) }
|
||||
func (s *DBBase) DBCount(beanPtr ormdb.IDBObj, wraper func(*xorm.Session) *xorm.Session) (int64, error) {
|
||||
return s.db.Count(beanPtr, wraper)
|
||||
}
|
||||
|
||||
func (s *DBBase) Stop() {
|
||||
if s.db != nil {
|
||||
s.db.Stop()
|
||||
}
|
||||
}
|
||||
func (s *DBBase) PageLoad(beanPtr ormdb.IDBObj, wraper func(*xorm.Session) *xorm.Session) (interface{}, error) {
|
||||
datas, err := s.db.PageLoad(beanPtr, wraper)
|
||||
if err != nil {
|
||||
return datas, err
|
||||
}
|
||||
s.setBase(datas)
|
||||
return datas, err
|
||||
}
|
||||
func (s *DBBase) LoadAll(beanPtr ormdb.IDBObj, wraper func(*xorm.Session) *xorm.Session) (interface{}, error) {
|
||||
datas, err := s.db.LoadAll(beanPtr, wraper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.setBase(datas)
|
||||
return datas, err
|
||||
}
|
||||
|
||||
func (s *DBBase) setBase(datas interface{}) {
|
||||
rd := reflect.ValueOf(datas)
|
||||
total := rd.Len()
|
||||
for i := 0; i < total; i++ {
|
||||
data := rd.Index(i).Interface().(ormdb.IDBObj)
|
||||
data.OnLoadObj(s.db, data)
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"app/internal/msg_inner"
|
||||
"core/actor/actor_msg"
|
||||
)
|
||||
|
||||
func (s *LoadBalanceManager) initAPI() {
|
||||
s.serviceBase.RegistMsg((*msg_inner.LoadBalanceReport)(nil), s.handLoadBalanceReport)
|
||||
}
|
||||
|
||||
func (s *LoadBalanceManager) handLoadBalanceReport(sourceId, data interface{}) {
|
||||
appId := sourceId.(*actor_msg.ActorId).Id
|
||||
msg := data.(*msg_inner.LoadBalanceReport)
|
||||
if _, ok := s.backendMap[appId]; !ok {
|
||||
s.backendMap[appId] = &LoadBalanceNode{
|
||||
appId: appId,
|
||||
address: msg.Address,
|
||||
rank: msg.Rank,
|
||||
isAlive: true,
|
||||
}
|
||||
} else {
|
||||
s.backendMap[appId].address = msg.Address
|
||||
s.backendMap[appId].rank = msg.Rank
|
||||
}
|
||||
if s.bestBackendAppId == "" {
|
||||
s.bestBackendAppId = appId
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"core/abtime"
|
||||
"core/prometheus"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Prometheus struct {
|
||||
registry *prometheus.Prometheus
|
||||
stype string
|
||||
sid string
|
||||
|
||||
handMsgNum *prometheus.CounterVec //客户端消息处理数量
|
||||
handMsgCost *prometheus.CounterVec //客户端消息处理耗时
|
||||
online *prometheus.GaugeVec //在线玩家数量
|
||||
battle_histogram *prometheus.HistogramVec //战斗耗时分布
|
||||
}
|
||||
|
||||
func (this *Prometheus) init(registry *prometheus.Prometheus, stype string, sid int32) {
|
||||
this.registry = registry
|
||||
this.stype = stype
|
||||
this.sid = strconv.Itoa(int(sid))
|
||||
subsystem := "service"
|
||||
this.handMsgNum = this.registry.RegCounter(subsystem, "msg_num", []string{"stype", "sid", "msg"})
|
||||
this.handMsgCost = this.registry.RegCounter(subsystem, "msg_cost", []string{"stype", "sid", "msg"})
|
||||
this.online = this.registry.RegGauge(subsystem, "online", []string{"sid"})
|
||||
this.battle_histogram = this.registry.RegHistogram(subsystem, "battle_his", []string{"sid"}, []float64{2, 4, 8, 16, 32, 64, 256, 512, 1024, 2048, 4096})
|
||||
}
|
||||
|
||||
func (this *Prometheus) RecordHandMsg(start time.Time, msg string) {
|
||||
cost := abtime.Now().Sub(start)
|
||||
if cost < 0 {
|
||||
cost = 0
|
||||
}
|
||||
this.handMsgNum.Inc(this.stype, this.sid, msg)
|
||||
this.handMsgCost.Add(float64(cost), this.stype, this.sid, msg)
|
||||
}
|
||||
|
||||
func (this *Prometheus) RecordOnline(num int) {
|
||||
this.online.Set(float64(num), this.sid)
|
||||
}
|
||||
|
||||
func (this *Prometheus) RecordBattle(t int64) {
|
||||
this.battle_histogram.Observe(float64(t), this.sid)
|
||||
}
|
||||
@ -1,130 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"app/internal/iniconfig"
|
||||
"app/internal/msg_inner"
|
||||
"app/internal/msg_util"
|
||||
"core/abtime"
|
||||
"core/actor"
|
||||
"core/dispatcher"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func New(appType string, appId int32) IServiceBase {
|
||||
service := &ServiceBase{
|
||||
appType: appType,
|
||||
appId: appId,
|
||||
config: iniconfig.NewAppConf(appType, appId),
|
||||
prometheus: &Prometheus{},
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
type IServiceBase interface {
|
||||
ITimerManager
|
||||
actor.IActorHandler
|
||||
dispatcher.IDispatcher
|
||||
IDBBase
|
||||
|
||||
SID() int32
|
||||
SType() string
|
||||
Config() *iniconfig.Config
|
||||
LoginKey() string
|
||||
|
||||
Parser() *msg_util.ProtoParser
|
||||
RegistMsg(msg interface{}, f msg_util.MsgFun)
|
||||
RegistReq(msg interface{}, f msg_util.ReqFun)
|
||||
Prometheus() *Prometheus
|
||||
RecordCost(handler http.HandlerFunc) http.HandlerFunc
|
||||
DependOn(targetId interface{}, f func())
|
||||
|
||||
VirtualUser() IVirtualUserManager
|
||||
LoadBalance() ILoadBalanceManager
|
||||
}
|
||||
|
||||
var _ IServiceBase = (*ServiceBase)(nil) //
|
||||
type ServiceBase struct {
|
||||
ITimerManager
|
||||
actor.ActorHanlerBase //actor
|
||||
dispatcher.Dispatcher //事件分发
|
||||
DBBase
|
||||
|
||||
appType string
|
||||
appId int32
|
||||
config *iniconfig.Config //game基础配置
|
||||
msgParser *msg_util.ProtoParser //协议解析器
|
||||
msgHandler *msg_util.MsgTypeHandler //actor消息处理
|
||||
prometheus *Prometheus //监控
|
||||
virtualUserMgr IVirtualUserManager //虚拟客户端
|
||||
loadBalanceMgr ILoadBalanceManager //负载均衡
|
||||
}
|
||||
|
||||
func (s *ServiceBase) OnStart() error {
|
||||
s.ITimerManager = NewTimerManager(s.Actor())
|
||||
s.DBBase.Init(s)
|
||||
s.prometheus.init(s.Actor().Prometheus(), s.SType(), s.SID())
|
||||
s.msgParser = msg_util.NewProtoParser("message", "MSG_TYPE")
|
||||
s.msgHandler = msg_util.NewMsgTypeHandler()
|
||||
s.virtualUserMgr = NewVirtualUserManager().Init(s)
|
||||
s.loadBalanceMgr = NewLoadBalanceManager().Init(s)
|
||||
s.registDependOn()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceBase) OnStop() bool {
|
||||
s.DBBase.Stop()
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *ServiceBase) registDependOn() {
|
||||
s.msgHandler.RegistReq((*msg_inner.CheckAlive)(nil), func(requestId, msg interface{}) {
|
||||
s.Actor().Response(requestId, msg)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceBase) DependOn(targetId interface{}, f func()) {
|
||||
var timerId int64
|
||||
s.Actor().Send(s.Actor().Id(), func() {
|
||||
timerId = s.Actor().AddTimer(time.Second, -1, func(dt int64) {
|
||||
if _, err := s.Actor().RequestWait(targetId, &msg_inner.CheckAlive{}); err == nil {
|
||||
if timerId != 0 { //保证只执行一次
|
||||
s.Actor().CancelTimer(timerId)
|
||||
timerId = 0
|
||||
f()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceBase) HandleMessage(sourceId, targetId, msg interface{}) {
|
||||
defer s.Prometheus().RecordHandMsg(abtime.Now(), msg_util.MsgName(msg))
|
||||
s.msgHandler.HandleMsg(sourceId, msg)
|
||||
}
|
||||
|
||||
func (s *ServiceBase) HandleRequest(sourceId, targetId, requestId, msg interface{}) {
|
||||
defer s.Prometheus().RecordHandMsg(abtime.Now(), msg_util.MsgName(msg))
|
||||
s.msgHandler.HandleReq(requestId, msg)
|
||||
}
|
||||
|
||||
func (s *ServiceBase) RegistMsg(msg interface{}, f msg_util.MsgFun) { s.msgHandler.RegistMsg(msg, f) }
|
||||
func (s *ServiceBase) RegistReq(msg interface{}, f msg_util.ReqFun) { s.msgHandler.RegistReq(msg, f) }
|
||||
func (s *ServiceBase) SID() int32 { return s.appId }
|
||||
func (s *ServiceBase) SType() string { return s.appType }
|
||||
func (s *ServiceBase) Config() *iniconfig.Config { return s.config }
|
||||
func (s *ServiceBase) Prometheus() *Prometheus { return s.prometheus }
|
||||
func (s *ServiceBase) VirtualUser() IVirtualUserManager { return s.virtualUserMgr }
|
||||
func (s *ServiceBase) LoadBalance() ILoadBalanceManager { return s.loadBalanceMgr }
|
||||
func (s *ServiceBase) Parser() *msg_util.ProtoParser { return s.msgParser }
|
||||
|
||||
func (s *ServiceBase) LoginKey() string {
|
||||
return s.config.MustString("login_key", "6^2f1onGbkK8iIW%vaC4b*2#oK4rwj&aOa%")
|
||||
}
|
||||
|
||||
func (s *ServiceBase) RecordCost(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
defer s.Prometheus().RecordHandMsg(abtime.Now(), request.URL.String())
|
||||
handler(writer, request)
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"core/abtime"
|
||||
"core/actor/timer"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ITimer interface {
|
||||
CancelTimer(timerId int64)
|
||||
AddTimer(interval time.Duration, times int32, callback timer.FuncCallback) int64
|
||||
}
|
||||
|
||||
type ITimerManager interface {
|
||||
AddTimer(interval time.Duration, trigger_times int32, callback timer.FuncCallback) int64
|
||||
AddScheduleTask(start time.Time, dur time.Duration, callback timer.FuncCallback)
|
||||
CancelTimer(timerId int64)
|
||||
ClearTimer()
|
||||
}
|
||||
|
||||
func NewTimerManager(timer ITimer) ITimerManager {
|
||||
return &TimerManager{timer: timer, timerIds: make(map[int64]bool)}
|
||||
}
|
||||
|
||||
type TimerManager struct {
|
||||
timer ITimer
|
||||
timerIds map[int64]bool
|
||||
}
|
||||
|
||||
func (this *TimerManager) AddTimer(interval time.Duration, trigger_times int32, callback timer.FuncCallback) int64 {
|
||||
timerId := this.timer.AddTimer(interval, trigger_times, callback)
|
||||
this.timerIds[timerId] = true
|
||||
return timerId
|
||||
}
|
||||
|
||||
// 周期性无限循环任务
|
||||
func (s *TimerManager) AddScheduleTask(start time.Time, dur time.Duration, callback timer.FuncCallback) {
|
||||
first := start.Sub(abtime.Now())
|
||||
s.AddTimer(first, 1, func(dt int64) { callback(dt); s.AddTimer(dur, -1, callback) })
|
||||
}
|
||||
|
||||
func (this *TimerManager) CancelTimer(timerId int64) {
|
||||
this.timer.CancelTimer(timerId)
|
||||
delete(this.timerIds, timerId)
|
||||
}
|
||||
|
||||
func (this *TimerManager) ClearTimer() {
|
||||
for timerId := range this.timerIds {
|
||||
this.CancelTimer(timerId)
|
||||
}
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/internal/msg_inner"
|
||||
"app/internal/service"
|
||||
"encoding/binary"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// 所有与客户端通信的actor,需要在本机注册角色的当前状态、注册gate等信息
|
||||
func NewVirtualUserManager() IVirtualUserManager {
|
||||
return &VirtualUserManager{
|
||||
userMap: make(map[int64]*VirtualUser),
|
||||
}
|
||||
}
|
||||
|
||||
type UserMsgRawFunc func(*msg_inner.VirtualUserMessage)
|
||||
type UserMsgFunc func(rid int64, data interface{}) (message.MSG_RESULT, proto.Message)
|
||||
type UserStatusFunc func(rid int64)
|
||||
|
||||
var _ IVirtualUserManager = (*VirtualUserManager)(nil) //interface实现检查
|
||||
type IVirtualUserManager interface {
|
||||
Init(serviceBase IServiceBase) IVirtualUserManager
|
||||
Send2User(rid int64, msg interface{})
|
||||
BroadCast2User(sid int32, msg interface{})
|
||||
GroupCast2User(ridList []int64, msg interface{})
|
||||
RegistUserMsg(msg interface{}, f UserMsgFunc)
|
||||
RegistUserMsgRaw(f UserMsgRawFunc)
|
||||
RegistUserOnline(f UserStatusFunc)
|
||||
RegistUserOffline(f UserStatusFunc)
|
||||
}
|
||||
|
||||
type VirtualUserManager struct {
|
||||
serviceBase IServiceBase
|
||||
|
||||
userMap map[int64]*VirtualUser //rid->user
|
||||
msgHandler *VirtualUserHandler //user消息处理
|
||||
msgRawHandler UserMsgRawFunc //user未解析消息处理
|
||||
userStatusOnline UserStatusFunc //user上线消息
|
||||
userStatusOffline UserStatusFunc //user离线消息
|
||||
}
|
||||
|
||||
type VirtualUser struct {
|
||||
serviceBase IServiceBase
|
||||
RID int64
|
||||
GID int32
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) Init(serviceBase IServiceBase) IVirtualUserManager {
|
||||
s.serviceBase = serviceBase
|
||||
s.msgHandler = NewVirtualUserHandler(s)
|
||||
|
||||
s.initAPI()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) BroadCast2User(sid int32, msg interface{}) {
|
||||
if data := s.getMessageData(msg); data != nil {
|
||||
s.serviceBase.Actor().Broadcast(service.Gate, &msg_inner.BroadCast2VirtualUser{
|
||||
SID: sid,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) GroupCast2User(ridList []int64, msg interface{}) {
|
||||
groupCastMap := make(map[int32][]int64) //sid->ridList
|
||||
if data := s.getMessageData(msg); data != nil {
|
||||
for _, rid := range ridList {
|
||||
if user, ok := s.userMap[rid]; ok {
|
||||
groupCastMap[user.GID] = append(groupCastMap[user.GID], rid)
|
||||
}
|
||||
}
|
||||
for gid, rids := range groupCastMap {
|
||||
s.serviceBase.Actor().Send(service.GateId(gid), &msg_inner.GroupCast2VirtualUser{
|
||||
RIDList: rids,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) Send2User(rid int64, msg interface{}) {
|
||||
if user, ok := s.userMap[rid]; ok {
|
||||
if data := s.getMessageData(msg); data != nil {
|
||||
s.serviceBase.Actor().Send(service.GateId(user.GID), &msg_inner.Send2VirtualUser{
|
||||
RID: user.RID,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) RegistUserMsg(msg interface{}, f UserMsgFunc) {
|
||||
s.msgHandler.RegistMsg(msg, f)
|
||||
}
|
||||
func (s *VirtualUserManager) RegistUserMsgRaw(f UserMsgRawFunc) {
|
||||
s.msgRawHandler = f
|
||||
}
|
||||
func (s *VirtualUserManager) RegistUserOnline(f UserStatusFunc) {
|
||||
s.userStatusOnline = f
|
||||
}
|
||||
func (s *VirtualUserManager) RegistUserOffline(f UserStatusFunc) {
|
||||
s.userStatusOffline = f
|
||||
}
|
||||
|
||||
func (s *VirtualUserManager) getMessageData(msg interface{}) []byte {
|
||||
if message, ok := msg.(proto.Message); ok {
|
||||
if msgId, ok2 := s.serviceBase.Parser().MsgToId(message); ok2 {
|
||||
if payload, err := proto.Marshal(message); err == nil {
|
||||
data := make([]byte, 6+len(payload))
|
||||
binary.BigEndian.PutUint32(data, uint32(len(payload)+6))
|
||||
binary.BigEndian.PutUint16(data[4:], uint16(msgId))
|
||||
copy(data[6:], payload)
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *VirtualUserManager) onUserMessage(mgsId int32, rid int64, msg interface{}) {
|
||||
s.msgHandler.HandleMessage(mgsId, rid, msg)
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"app/internal/msg_inner"
|
||||
"core/log"
|
||||
)
|
||||
|
||||
func (s *VirtualUserManager) initAPI() {
|
||||
s.serviceBase.RegistMsg((*msg_inner.VirtualUserCreate)(nil), s.handUserCreate)
|
||||
s.serviceBase.RegistMsg((*msg_inner.VirtualUserDestroy)(nil), s.handUserDestroy)
|
||||
s.serviceBase.RegistMsg((*msg_inner.VirtualUserMessage)(nil), s.handUserMessage)
|
||||
}
|
||||
|
||||
func (this *VirtualUserManager) handUserCreate(sourceId, data interface{}) {
|
||||
msg := data.(*msg_inner.VirtualUserCreate)
|
||||
if user, ok := this.userMap[msg.RID]; ok {
|
||||
user.GID = msg.GID
|
||||
} else {
|
||||
this.userMap[msg.RID] = &VirtualUser{
|
||||
RID: msg.RID,
|
||||
GID: msg.GID,
|
||||
}
|
||||
}
|
||||
if this.userStatusOnline != nil {
|
||||
this.userStatusOnline(msg.RID)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *VirtualUserManager) handUserDestroy(sourceId, data interface{}) {
|
||||
msg := data.(*msg_inner.VirtualUserDestroy)
|
||||
delete(this.userMap, msg.RID)
|
||||
if this.userStatusOffline != nil {
|
||||
this.userStatusOffline(msg.RID)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *VirtualUserManager) handUserMessage(sourceId, data interface{}) {
|
||||
msg := data.(*msg_inner.VirtualUserMessage)
|
||||
if this.msgRawHandler != nil {
|
||||
this.msgRawHandler(msg)
|
||||
} else {
|
||||
if message, ok := this.serviceBase.Parser().Unmarshal(msg.MsgId, msg.Data); ok {
|
||||
this.onUserMessage(msg.MsgId, msg.RID, message)
|
||||
} else {
|
||||
log.KV("MsgId", msg.MsgId).Error("VirtualUserMessage Unmarshal err")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
package service_base
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"core/actor/actor_msg"
|
||||
"core/tools"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func NewVirtualUserHandler(mgr IVirtualUserManager) *VirtualUserHandler {
|
||||
return &VirtualUserHandler{
|
||||
mgr: mgr,
|
||||
msgMap: make(map[string]UserMsgFunc),
|
||||
}
|
||||
}
|
||||
|
||||
type VirtualUserHandler struct {
|
||||
mgr IVirtualUserManager
|
||||
msgMap map[string]UserMsgFunc
|
||||
}
|
||||
|
||||
// 注册消息回调
|
||||
func (h *VirtualUserHandler) RegistMsg(msg interface{}, f UserMsgFunc) {
|
||||
msgName := MsgName(msg)
|
||||
_, ok := h.msgMap[msgName]
|
||||
tools.AssertTrue(!ok, "regist repeated msg=%v", msgName)
|
||||
h.msgMap[msgName] = f
|
||||
}
|
||||
|
||||
func (h *VirtualUserHandler) HandleMessage(msgId int32, rid int64, msg interface{}) bool {
|
||||
msgName := MsgName(msg)
|
||||
handler := h.msgMap[msgName]
|
||||
tools.AssertTrue(handler != nil, "msg=%v not regist handler", msgName)
|
||||
result, resultMsg := handler(rid, msg)
|
||||
if resultMsg != nil {
|
||||
data, err := proto.Marshal(resultMsg)
|
||||
tools.AssertTrue(err == nil, "msg=%v Marshal err: %v", msgName, err)
|
||||
h.mgr.Send2User(rid, &message.MessageResult{
|
||||
ProtoId: msgId,
|
||||
Result: result,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func MsgName(msg interface{}) string { return actor_msg.MsgName(msg) }
|
||||
@ -1,41 +0,0 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"app/servers/login/model"
|
||||
"core/log"
|
||||
"core/tools"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (s *Login) initCmd() {
|
||||
s.Actor().RegistCmd("game_info", s.cmdGameInfo)
|
||||
s.Actor().RegistCmd("dev_login", s.cmdDevLogin)
|
||||
s.Actor().RegistCmd("white_ip", s.cmdWhiteIP)
|
||||
}
|
||||
|
||||
func (s *Login) cmdGameInfo(param string) ([]byte, error) {
|
||||
log.KV("param", param).Info("cmdGameInfo")
|
||||
|
||||
games := []*model.GameServer{}
|
||||
s.gameServerMgr.RangeServers(func(server *model.GameServer) (stop bool) {
|
||||
games = append(games, server)
|
||||
return true
|
||||
})
|
||||
return json.Marshal(games)
|
||||
}
|
||||
|
||||
func (s *Login) cmdDevLogin(param string) ([]byte, error) {
|
||||
log.KV("param", param).Info("cmdDevLogin")
|
||||
|
||||
tools.AssertTrue(len(param) > 0, "param length error")
|
||||
s.loginHandler.SetDevLogin(param)
|
||||
return []byte("success"), nil
|
||||
}
|
||||
|
||||
func (s *Login) cmdWhiteIP(param string) ([]byte, error) {
|
||||
log.KV("param", param).Info("cmdWhiteIP")
|
||||
|
||||
tools.AssertTrue(len(param) > 0, "param length error")
|
||||
s.userMgr.SetWhiteIP(param)
|
||||
return []byte("success"), nil
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/internal/service_base"
|
||||
)
|
||||
|
||||
type ILogin interface {
|
||||
service_base.IServiceBase
|
||||
Debug() bool
|
||||
UserMgr() IUserManager
|
||||
GameMgr() IGameManager
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/login/model"
|
||||
)
|
||||
|
||||
type IGameManager interface {
|
||||
GetGameServer(sid int32) *model.GameServer
|
||||
SelectGame(isWhite bool) *model.GameServer
|
||||
RangeServers(fn func(server *model.GameServer) (stop bool))
|
||||
ABTestServer(abtest string) int32
|
||||
ABTestCDN(abtest string) string
|
||||
RandABTest() string
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/login/model"
|
||||
)
|
||||
|
||||
const AUDI_SID = 999 //审核服
|
||||
type IUserManager interface {
|
||||
Login(passport string, ptype string, rid int64, version, ip, packageCode string) (*model.Role, *model.GameUser, *model.GameServer)
|
||||
GetUser(passport string, ptype string) *model.GameUser
|
||||
NewUser(passport, ptype string, ip string, abtest string) *model.GameUser
|
||||
NewRole(passport, ptype string, ip string, sid int32) *model.Role
|
||||
|
||||
//客户端审核版本号
|
||||
UpdateAudit(version string)
|
||||
IsAudit(version string) bool
|
||||
//白名单账号
|
||||
UpdateUserWhite(uid int64, white bool)
|
||||
IsWhite(user *model.GameUser, ip string) bool
|
||||
IsWhiteIP(ip string) bool
|
||||
|
||||
UpdateUserSuper(uid int64, super bool) bool
|
||||
UpdateUserBan(uid int64, deadline, bancode int64) bool
|
||||
UpdateUserMute(uid int64, deadline int64) bool
|
||||
GetUserRoleList(uid int64) []*model.Role
|
||||
HasRoleBySID(uid int64, sid int32) bool
|
||||
GetSID(rids []int64) []int32
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package fathers
|
||||
|
||||
type ISDK interface {
|
||||
Verify(passport string, ptype string, extra string) bool
|
||||
}
|
||||
@ -1,391 +0,0 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"app/internal/service"
|
||||
"app/servers/login/logic/fathers"
|
||||
"app/servers/login/model"
|
||||
"core/abtime"
|
||||
"core/actor/actor_msg"
|
||||
"core/goroutine"
|
||||
"core/log"
|
||||
"core/tools"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func New(login fathers.ILogin) *LoginHandler {
|
||||
lh := &LoginHandler{
|
||||
login: login,
|
||||
sdk: map[string]fathers.ISDK{},
|
||||
}
|
||||
return lh
|
||||
}
|
||||
|
||||
type LoginHandler struct {
|
||||
login fathers.ILogin
|
||||
sdk map[string]fathers.ISDK
|
||||
devLogin sync.Map
|
||||
}
|
||||
|
||||
func (this *LoginHandler) HttpToMainLoop(fn func()) {
|
||||
var handler actor_msg.RequestWaitMsg = func(requestId interface{}) {
|
||||
goroutine.Try(fn, nil)
|
||||
this.login.Actor().Response(requestId, nil)
|
||||
}
|
||||
_, err := this.login.Actor().RequestWait(this.login.Actor().Id(), handler)
|
||||
tools.AssertNil(err)
|
||||
}
|
||||
|
||||
func (this *LoginHandler) SetDevLogin(passport string) {
|
||||
if _, ok := this.devLogin.Load(passport); ok {
|
||||
this.devLogin.Delete(passport)
|
||||
} else {
|
||||
this.devLogin.Store(passport, true)
|
||||
}
|
||||
|
||||
passports := []string{}
|
||||
this.devLogin.Range(func(key, value any) bool {
|
||||
passports = append(passports, key.(string))
|
||||
return true
|
||||
})
|
||||
log.KV("devlogin", passports).Info("devlogin list")
|
||||
}
|
||||
|
||||
func (this *LoginHandler) CanDevLogin(passport, ip string) bool {
|
||||
if this.login.Debug() {
|
||||
return true
|
||||
}
|
||||
_, ok := this.devLogin.Load(passport)
|
||||
return ok || this.login.UserMgr().IsWhiteIP(ip)
|
||||
}
|
||||
|
||||
func (this *LoginHandler) HandLogin(w http.ResponseWriter, r *http.Request) {
|
||||
type LoginReq struct {
|
||||
Passport string //账号
|
||||
PassportType string //账号类型
|
||||
OS string //操作系统
|
||||
Version string //客户端版本号
|
||||
RID int64 //角色ID(0=由服务器分配)
|
||||
Extra string //sdk额外数据
|
||||
PackageCode string //客户端包名
|
||||
Channels int32 //渠道
|
||||
DeviceModel string //设备类型
|
||||
TypeOfNetwork string //网络
|
||||
}
|
||||
|
||||
type LoginResp struct {
|
||||
Code int32 //成功码
|
||||
RID int64 //玩家RID
|
||||
UID int64 //玩家UID
|
||||
SID int32 //服务器Id
|
||||
GameServerAddr string //服务器ip:port
|
||||
GameServerAddrSource string //服务器ip:port
|
||||
Mute int64 //禁言截止时间
|
||||
Ban int64 //封号截止时间
|
||||
BanCode int64 //封号的原因.
|
||||
Super bool //是否GM账号
|
||||
Session string //登录session
|
||||
Timestamp int64 //登录时间
|
||||
MaintainTime int64 //维护结束时间
|
||||
RoleCreateTime int64 //角色创建时间
|
||||
UserCreateTime int64 //账号创建时间
|
||||
White bool
|
||||
UploadLog bool
|
||||
RoleName string
|
||||
RoleLevel int32
|
||||
}
|
||||
|
||||
const (
|
||||
Success = iota
|
||||
ReqErr //请求解析失败
|
||||
SDKErr //sdk验证失败
|
||||
PassportTypeUndefine //渠道未定义
|
||||
UserNotFind //用户未找到
|
||||
UserBan //封号
|
||||
Maintain //维护中
|
||||
CanNotDev //没有调试登录权限
|
||||
)
|
||||
|
||||
resp := &LoginResp{Code: ReqErr, Timestamp: abtime.Now().Unix()}
|
||||
defer tools.HttpResponse(w, resp)
|
||||
|
||||
req := &LoginReq{}
|
||||
if _, ok := tools.HttpUnmarshalBody(r, req); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
var ok bool
|
||||
|
||||
sdk, ok := this.sdk[req.PassportType]
|
||||
if !ok {
|
||||
resp.Code = PassportTypeUndefine
|
||||
return
|
||||
}
|
||||
|
||||
if !sdk.Verify(req.Passport, req.PassportType, req.Extra) && !this.CanDevLogin(req.Passport, ip) {
|
||||
resp.Code = SDKErr
|
||||
return
|
||||
}
|
||||
|
||||
this.HttpToMainLoop(func() {
|
||||
role, user, game := this.login.UserMgr().Login(req.Passport, req.PassportType, req.RID, req.Version, ip, req.PackageCode)
|
||||
if game == nil || game.Status == service.StatusClose {
|
||||
resp.MaintainTime = abtime.Now().Unix() + 8*3600
|
||||
resp.Code = Maintain
|
||||
return
|
||||
}
|
||||
|
||||
if game.Status < service.StatusOpen && !this.login.UserMgr().IsWhite(user, ip) {
|
||||
resp.MaintainTime = game.Maintain()
|
||||
resp.Code = Maintain
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil || role == nil {
|
||||
resp.Code = UserNotFind
|
||||
return
|
||||
}
|
||||
|
||||
if user.Ban > abtime.Now().Unix() {
|
||||
resp.Code = UserBan
|
||||
resp.BanCode = user.BanCode
|
||||
return
|
||||
}
|
||||
|
||||
addr, _ := this.login.LoadBalance().GetBestBackend()
|
||||
if addr == "" {
|
||||
resp.MaintainTime = abtime.Now().Unix() + 8*3600
|
||||
resp.Code = Maintain
|
||||
return
|
||||
}
|
||||
|
||||
resp.GameServerAddr = addr
|
||||
resp.GameServerAddrSource = addr
|
||||
|
||||
resp.RID = role.RID
|
||||
resp.UID = user.UID
|
||||
resp.Ban = user.Ban
|
||||
resp.Mute = user.Mute
|
||||
resp.Super = user.Super
|
||||
resp.SID = role.SID
|
||||
resp.Timestamp = role.LastLogin
|
||||
resp.Session = user.LastSession
|
||||
resp.UserCreateTime = user.CreatedAt
|
||||
resp.RoleCreateTime = role.CreatedAt
|
||||
resp.White = this.login.UserMgr().IsWhite(user, ip)
|
||||
resp.UploadLog = false
|
||||
resp.RoleName = role.Name
|
||||
resp.RoleLevel = role.TownhallLv
|
||||
|
||||
if user.IsNew {
|
||||
user.IsNew = false
|
||||
user.Update()
|
||||
}
|
||||
resp.Code = Success
|
||||
})
|
||||
}
|
||||
|
||||
func (this *LoginHandler) HandNewRole(w http.ResponseWriter, r *http.Request) {
|
||||
type Req struct {
|
||||
Passport string //账号
|
||||
PassportType string //账号类型
|
||||
SID int32 //指定服务器地址
|
||||
Session string //登录session
|
||||
}
|
||||
|
||||
type Resp struct {
|
||||
Code int32 //成功码
|
||||
RID int64 //玩家RID
|
||||
SID int32 //服务器Id
|
||||
}
|
||||
|
||||
const (
|
||||
Success = iota
|
||||
ReqErr
|
||||
CanNotDev
|
||||
UserNotFind
|
||||
UserBan
|
||||
NeedLogin
|
||||
GameIsFull
|
||||
NewRoleFailed
|
||||
)
|
||||
|
||||
resp := &Resp{Code: ReqErr}
|
||||
defer tools.HttpResponse(w, resp)
|
||||
|
||||
req := &Req{}
|
||||
if _, ok := tools.HttpUnmarshalBody(r, req); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
|
||||
this.HttpToMainLoop(func() {
|
||||
user := this.login.UserMgr().GetUser(req.Passport, req.PassportType)
|
||||
if user == nil {
|
||||
resp.Code = UserNotFind
|
||||
return
|
||||
}
|
||||
|
||||
if user.Ban > abtime.Now().Unix() {
|
||||
resp.Code = UserBan
|
||||
return
|
||||
}
|
||||
|
||||
if req.Session != user.LastSession {
|
||||
resp.Code = NeedLogin
|
||||
return
|
||||
}
|
||||
|
||||
game := this.login.GameMgr().GetGameServer(req.SID)
|
||||
if game == nil || !game.CanNewRole(this.login.UserMgr().IsWhite(user, ip)) {
|
||||
resp.Code = GameIsFull
|
||||
return
|
||||
}
|
||||
|
||||
newRole := this.login.UserMgr().NewRole(req.Passport, req.PassportType, ip, req.SID)
|
||||
if newRole == nil {
|
||||
resp.Code = NewRoleFailed
|
||||
return
|
||||
}
|
||||
|
||||
resp.RID = newRole.RID
|
||||
resp.SID = newRole.SID
|
||||
resp.Code = Success
|
||||
})
|
||||
}
|
||||
|
||||
func (this *LoginHandler) HandRoleList(w http.ResponseWriter, r *http.Request) {
|
||||
type Req struct {
|
||||
Passport string //账号
|
||||
PassportType string //账号类型
|
||||
Session string //登录session
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
RID int64 //角色Id
|
||||
SID int32 //角色所在服
|
||||
Icon string //头像
|
||||
Name string //角色名
|
||||
League string //联盟短名字
|
||||
Power int64 //战力
|
||||
TownhallLv int32 //主城等级
|
||||
}
|
||||
|
||||
type Resp struct {
|
||||
Code int32 //成功码
|
||||
Roles []*Role //角色列表
|
||||
}
|
||||
|
||||
const (
|
||||
Success = iota
|
||||
ReqErr
|
||||
UserNotFind
|
||||
NeedLogin
|
||||
CanNotDev
|
||||
)
|
||||
|
||||
resp := &Resp{Code: ReqErr}
|
||||
defer tools.HttpResponse(w, resp)
|
||||
|
||||
req := &Req{}
|
||||
if _, ok := tools.HttpUnmarshalBody(r, req); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
this.HttpToMainLoop(func() {
|
||||
user := this.login.UserMgr().GetUser(req.Passport, req.PassportType)
|
||||
if user == nil {
|
||||
resp.Code = UserNotFind
|
||||
return
|
||||
}
|
||||
|
||||
if req.Session != user.LastSession {
|
||||
resp.Code = NeedLogin
|
||||
return
|
||||
}
|
||||
|
||||
for _, role := range this.login.UserMgr().GetUserRoleList(user.UID) {
|
||||
if user.ABTest == "" && role.SID > fathers.AUDI_SID && !user.Super {
|
||||
continue
|
||||
}
|
||||
resp.Roles = append(resp.Roles, &Role{RID: role.RID, SID: role.SID, Icon: role.Icon, Name: role.Name, League: role.League, TownhallLv: role.TownhallLv, Power: role.Power})
|
||||
}
|
||||
resp.Code = Success
|
||||
})
|
||||
}
|
||||
|
||||
func (this *LoginHandler) HandServerList(w http.ResponseWriter, r *http.Request) {
|
||||
type Req struct {
|
||||
Version string //客户端版本号
|
||||
Passport string //账号
|
||||
PassportType string //账号类型
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
SID int32
|
||||
Name string
|
||||
Status service.GameServerStatus
|
||||
}
|
||||
|
||||
type Resp struct {
|
||||
Code int
|
||||
Servers []*Server
|
||||
}
|
||||
|
||||
const (
|
||||
Success = iota
|
||||
ReqErr
|
||||
CanNotDev
|
||||
UserNotFound
|
||||
)
|
||||
|
||||
resp := &Resp{Code: ReqErr}
|
||||
defer tools.HttpResponse(w, resp)
|
||||
|
||||
req := &Req{}
|
||||
if _, ok := tools.HttpUnmarshalBody(r, req); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
this.HttpToMainLoop(func() {
|
||||
user := this.login.UserMgr().GetUser(req.Passport, req.PassportType)
|
||||
if user == nil {
|
||||
resp.Code = UserNotFound
|
||||
return
|
||||
}
|
||||
|
||||
if user.Super {
|
||||
this.login.GameMgr().RangeServers(func(server *model.GameServer) (stop bool) {
|
||||
if server.Status > service.StatusClose {
|
||||
resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
}
|
||||
return
|
||||
})
|
||||
} else if this.login.UserMgr().IsAudit(req.Version) {
|
||||
if server := this.login.GameMgr().GetGameServer(fathers.AUDI_SID); server != nil && server.Status > service.StatusClose {
|
||||
resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
}
|
||||
} else if sid := this.login.GameMgr().ABTestServer(user.ABTest); sid > fathers.AUDI_SID {
|
||||
if server := this.login.GameMgr().GetGameServer(sid); server != nil && server.Status > service.StatusClose {
|
||||
resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
}
|
||||
} else {
|
||||
this.login.GameMgr().RangeServers(func(server *model.GameServer) (stop bool) {
|
||||
if server.Status > service.StatusClose && server.ServerId < fathers.AUDI_SID {
|
||||
//hasS3 := this.login.UserMgr().HasRoleBySID(user.UID, 3)
|
||||
//if hasS3 && server.ServerId == 3 {
|
||||
// resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
//} else if !hasS3 && server.ServerId != 3 {
|
||||
// resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
//}
|
||||
resp.Servers = append(resp.Servers, &Server{SID: server.ServerId, Name: server.ServerName, Status: server.Status})
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
resp.Code = Success
|
||||
})
|
||||
}
|
||||
@ -1,137 +0,0 @@
|
||||
package mgr_game
|
||||
|
||||
import (
|
||||
"app/internal/service"
|
||||
"app/servers/login/logic/fathers"
|
||||
"app/servers/login/model"
|
||||
"core/log"
|
||||
"core/tools"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func New(login fathers.ILogin) *GameServerManager {
|
||||
return &GameServerManager{
|
||||
login: login,
|
||||
}
|
||||
}
|
||||
|
||||
type GameServerManager struct {
|
||||
login fathers.ILogin
|
||||
allGames sync.Map
|
||||
recommendGames sync.Map
|
||||
|
||||
abtests map[string]int32
|
||||
clientCDNs map[string]string
|
||||
newABTests []string
|
||||
newABTestNum int
|
||||
}
|
||||
|
||||
func (this *GameServerManager) Init() *GameServerManager {
|
||||
tools.AssertNil(this.login.CreateTable(&model.GameServer{}))
|
||||
data, err := this.login.PageLoad(&model.GameServer{}, nil)
|
||||
tools.AssertNil(err)
|
||||
gameservers := data.([]*model.GameServer)
|
||||
if len(gameservers) == 0 {
|
||||
testNew := &model.GameServer{
|
||||
ServerId: 1,
|
||||
Status: service.StatusOpen,
|
||||
MaxRoleNum: 1000,
|
||||
}
|
||||
this.allGames.Store(testNew.ServerId, testNew)
|
||||
} else {
|
||||
for _, game := range data.([]*model.GameServer) {
|
||||
this.allGames.Store(game.ServerId, game)
|
||||
if game.Recommend {
|
||||
this.recommendGames.Store(game.ServerId, game)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.initABTest()
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *GameServerManager) SelectGame(isWhite bool) (selectGame *model.GameServer) {
|
||||
this.recommendGames.Range(func(key, value interface{}) bool {
|
||||
game := value.(*model.GameServer)
|
||||
if game.CanNewRole(isWhite) && game.ServerId < fathers.AUDI_SID {
|
||||
selectGame = game
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if selectGame != nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.allGames.Range(func(key, value interface{}) bool {
|
||||
game := value.(*model.GameServer)
|
||||
if game.CanNewRole(isWhite) && game.ServerId < fathers.AUDI_SID {
|
||||
selectGame = game
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (this *GameServerManager) GetGameServer(sid int32) *model.GameServer {
|
||||
gameServer, ok := this.allGames.Load(sid)
|
||||
if !ok {
|
||||
log.KV("sid", sid).WarnStack(1, "sid not find")
|
||||
this.allGames.Range(func(key, value interface{}) bool {
|
||||
log.KV("info", value).Warn("server info")
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
}
|
||||
return gameServer.(*model.GameServer)
|
||||
}
|
||||
|
||||
func (this *GameServerManager) RangeServers(fn func(server *model.GameServer) (stop bool)) {
|
||||
this.allGames.Range(func(key, value interface{}) bool {
|
||||
if fn(value.(*model.GameServer)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (this *GameServerManager) initABTest() {
|
||||
this.abtests = map[string]int32{}
|
||||
this.clientCDNs = map[string]string{}
|
||||
abtests := this.login.Config().ChildSections()
|
||||
for _, abtest := range abtests {
|
||||
if strings.Index(abtest.Name(), "abtest") < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
game_id := abtest.Key("game_id").MustInt(0)
|
||||
name := abtest.Key("name").String()
|
||||
this.clientCDNs[name] = abtest.Key("client_cdn").String()
|
||||
if abtest.Key("new_user").MustBool(false) {
|
||||
this.abtests[name] = int32(game_id)
|
||||
this.newABTests = append(this.newABTests, name)
|
||||
} else {
|
||||
this.abtests[name] = int32(game_id)
|
||||
}
|
||||
}
|
||||
log.KV("new_user", this.newABTests).KV("games", this.abtests).KV("cdn", this.clientCDNs).Info("init abtest")
|
||||
}
|
||||
|
||||
func (this *GameServerManager) ABTestServer(abtest string) int32 {
|
||||
return this.abtests[abtest]
|
||||
}
|
||||
|
||||
func (this *GameServerManager) ABTestCDN(abtest string) string {
|
||||
return this.clientCDNs[abtest]
|
||||
}
|
||||
|
||||
func (this *GameServerManager) RandABTest() string {
|
||||
if l := len(this.newABTests); l > 0 {
|
||||
this.newABTestNum++
|
||||
return this.newABTests[this.newABTestNum%l]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@ -1,358 +0,0 @@
|
||||
package mgr_user
|
||||
|
||||
import (
|
||||
"app/servers/internal/app_tools"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"app/servers/login/logic/fathers"
|
||||
"app/servers/login/model"
|
||||
"core/abtime"
|
||||
"core/log"
|
||||
"core/tools"
|
||||
)
|
||||
|
||||
func New(login fathers.ILogin) *UserManager {
|
||||
mgr := &UserManager{
|
||||
login: login,
|
||||
roles: map[int64]*model.Role{},
|
||||
users: map[int64]*model.GameUser{},
|
||||
passports: map[string]*model.Passport{},
|
||||
}
|
||||
snode, err := tools.NewSnowflakeNode(int64(login.SID()))
|
||||
tools.AssertNil(err)
|
||||
mgr.uidCreator = snode
|
||||
mgr.ridCreator = NewRIDCreator(login.SID())
|
||||
return mgr
|
||||
}
|
||||
|
||||
type UserManager struct {
|
||||
login fathers.ILogin
|
||||
roles map[int64]*model.Role
|
||||
users map[int64]*model.GameUser
|
||||
passports map[string]*model.Passport
|
||||
auditVersion sync.Map //审核版本号
|
||||
uidCreator *tools.SnowflakeNode
|
||||
ridCreator *RIDCreator
|
||||
whiteIP sync.Map
|
||||
}
|
||||
|
||||
func (this *UserManager) Init() *UserManager {
|
||||
tools.AssertNil(this.login.CreateTable(&model.GameUser{}))
|
||||
|
||||
data, err := this.login.PageLoad(&model.GameUser{}, nil)
|
||||
tools.AssertNil(err)
|
||||
|
||||
datas := data.([]*model.GameUser)
|
||||
for _, user := range datas {
|
||||
this.users[user.UID] = user
|
||||
}
|
||||
|
||||
tools.AssertNil(this.login.CreateTable(&model.Role{}))
|
||||
data, err = this.login.PageLoad(&model.Role{}, nil)
|
||||
tools.AssertNil(err)
|
||||
roleRows := data.([]*model.Role)
|
||||
for _, role := range roleRows {
|
||||
this.roles[role.RID] = role
|
||||
this.ridCreator.Add(role.RID)
|
||||
}
|
||||
|
||||
tools.AssertNil(this.login.CreateTable(&model.Passport{}))
|
||||
data, err = this.login.PageLoad(&model.Passport{}, nil)
|
||||
tools.AssertNil(err)
|
||||
passportRows := data.([]*model.Passport)
|
||||
for _, passport := range passportRows {
|
||||
key := app_tools.PassportMerge(passport.PID, passport.Type)
|
||||
this.passports[key] = passport
|
||||
}
|
||||
|
||||
//if user := this.GetUser("703480445736910631", "goat"); user != nil && !user.Roles[2306541] {
|
||||
// user.Super = true
|
||||
// this.newRole("703480445736910631", "goat", "", 1, 2306541)
|
||||
// this.newRole("703480445736910631", "goat", "", 1, 4699161)
|
||||
// this.newRole("703480445736910631", "goat", "", 1, 6792871)
|
||||
// this.newRole("703480445736910631", "goat", "", 1, 3054520)
|
||||
// this.newRole("703480445736910631", "goat", "", 2, 5642957)
|
||||
// this.ridCreator.Add(2306541)
|
||||
// this.ridCreator.Add(4699161)
|
||||
// this.ridCreator.Add(6792871)
|
||||
// this.ridCreator.Add(3054520)
|
||||
// this.ridCreator.Add(5642957)
|
||||
//}
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *UserManager) GetUserRoleList(uid int64) []*model.Role {
|
||||
user := this.users[uid]
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var roles []*model.Role
|
||||
for rid, _ := range user.Roles {
|
||||
if role := this.getUserRole(user.UID, rid); role != nil {
|
||||
roles = append(roles, role)
|
||||
}
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
||||
func (this *UserManager) HasRoleBySID(uid int64, sid int32) bool {
|
||||
user := this.users[uid]
|
||||
if user == nil {
|
||||
return false
|
||||
}
|
||||
for rid, _ := range user.Roles {
|
||||
if role := this.getUserRole(user.UID, rid); role != nil {
|
||||
if role.SID == sid {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *UserManager) getUserRole(uid int64, rid int64) *model.Role {
|
||||
if uRole := this.roles[rid]; uRole != nil && uRole.UID == uid {
|
||||
return uRole
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *UserManager) SetWhiteIP(ip string) {
|
||||
if _, ok := this.whiteIP.Load(ip); ok {
|
||||
this.whiteIP.Delete(ip)
|
||||
} else {
|
||||
this.whiteIP.Store(ip, true)
|
||||
}
|
||||
|
||||
ips := []string{}
|
||||
this.whiteIP.Range(func(key, value any) bool {
|
||||
ips = append(ips, key.(string))
|
||||
return true
|
||||
})
|
||||
log.KV("whiteip", ips).Info("whiteip list")
|
||||
}
|
||||
|
||||
func (this *UserManager) IsWhite(user *model.GameUser, ip string) bool {
|
||||
return user.White || this.IsWhiteIP(ip)
|
||||
}
|
||||
|
||||
func (this *UserManager) IsWhiteIP(ip string) bool {
|
||||
_, ok := this.whiteIP.Load(ip)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (this *UserManager) Login(passport string, ptype string, rid int64, version, ip, packageCode string) (role *model.Role, user *model.GameUser, game *model.GameServer) {
|
||||
pport := this.passports[app_tools.PassportMerge(passport, ptype)]
|
||||
if pport == nil {
|
||||
user = this.NewUser(passport, ptype, ip, "")
|
||||
} else {
|
||||
user = this.users[pport.UID]
|
||||
}
|
||||
if user == nil {
|
||||
log.KV("pport", passport).KV("ptype", ptype).Error("user is nil")
|
||||
return
|
||||
}
|
||||
|
||||
role = this.getUserRole(user.UID, rid)
|
||||
if lastRole := this.getUserRole(user.UID, user.LastLoginRID); role == nil && lastRole != nil { //没有选就用最近一次登录角色登录
|
||||
role = lastRole
|
||||
}
|
||||
|
||||
if this.IsAudit(version) { //审核包只能进审核服
|
||||
game = this.login.GameMgr().GetGameServer(fathers.AUDI_SID)
|
||||
if role != nil && role.SID != fathers.AUDI_SID {
|
||||
role = nil
|
||||
for _, arole := range this.GetUserRoleList(user.UID) {
|
||||
if arole.SID == fathers.AUDI_SID {
|
||||
role = arole
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if absid := this.login.GameMgr().ABTestServer(user.ABTest); absid > fathers.AUDI_SID { //abtest只能进abtest服
|
||||
game = this.login.GameMgr().GetGameServer(absid)
|
||||
if role != nil && role.SID != absid {
|
||||
role = nil
|
||||
for _, abrole := range this.GetUserRoleList(user.UID) {
|
||||
if abrole.SID == absid {
|
||||
role = abrole
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if role != nil && user.ABTest == "" && role.SID > fathers.AUDI_SID && !user.Super {
|
||||
role = nil
|
||||
}
|
||||
|
||||
if role == nil {
|
||||
roles := this.GetUserRoleList(user.UID)
|
||||
sort.Slice(roles, func(i, j int) bool { return roles[i].TownhallLv > roles[j].TownhallLv })
|
||||
for _, has := range roles {
|
||||
if user.ABTest == "" && has.SID > fathers.AUDI_SID && !user.Super {
|
||||
continue
|
||||
}
|
||||
role = has
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if role != nil {
|
||||
game = this.login.GameMgr().GetGameServer(role.SID)
|
||||
} else {
|
||||
game = this.login.GameMgr().SelectGame(this.login.UserMgr().IsWhite(user, ip))
|
||||
}
|
||||
}
|
||||
|
||||
if game == nil {
|
||||
log.KV("pport", passport).KV("ptype", ptype).Error("game is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if role == nil {
|
||||
if role = this.NewRole(passport, ptype, ip, game.ServerId); role == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user.LastLoginRID = role.RID
|
||||
user.LastLogin = abtime.Now().Unix()
|
||||
role.LastLogin = user.LastLogin
|
||||
user.LastSession = app_tools.LoginSession(this.login.LoginKey(), role.SID, role.RID, user.UID, user.LastLogin, user.Mute, user.Ban, user.Super)
|
||||
user.PackageCode = packageCode
|
||||
user.Update()
|
||||
role.Update()
|
||||
log.KV("passport", passport).KV("ptype", ptype).KV("uid", user.UID).KV("rid", role.RID).KV("session", user.LastSession).Info("login success")
|
||||
return
|
||||
}
|
||||
|
||||
func (this *UserManager) GetUser(passport string, ptype string) *model.GameUser {
|
||||
pport := this.passports[app_tools.PassportMerge(passport, ptype)]
|
||||
if pport != nil {
|
||||
return this.users[pport.UID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *UserManager) NewUser(passport, ptype string, ip string, abtest string) *model.GameUser {
|
||||
newUser := model.NewUser(this.login, this.uidCreator.ID(), ip, abtest)
|
||||
this.users[newUser.UID] = newUser
|
||||
newUser.Update()
|
||||
|
||||
newPassport := model.NewPassport(this.login, newUser.UID, passport, ptype, ip)
|
||||
newPassport.Update()
|
||||
this.passports[app_tools.PassportMerge(passport, ptype)] = newPassport
|
||||
log.KV("pport", passport).KV("ptype", ptype).KV("uid", newUser.UID).KV("abtest", abtest).InfoStack(1, "NewUser")
|
||||
return newUser
|
||||
}
|
||||
|
||||
func (this *UserManager) NewRole(passport, ptype string, ip string, sid int32) *model.Role {
|
||||
return this.newRole(passport, ptype, ip, sid, this.ridCreator.ID(sid))
|
||||
}
|
||||
|
||||
func (this *UserManager) newRole(passport, ptype string, ip string, sid int32, rid int64) *model.Role {
|
||||
pport := this.passports[app_tools.PassportMerge(passport, ptype)]
|
||||
tools.AssertTrue(pport != nil, "newrole pport=%v ptype=%v not find", passport, ptype)
|
||||
|
||||
user := this.users[pport.UID]
|
||||
tools.AssertTrue(user != nil, "newrole uid=%v not find", pport.UID)
|
||||
|
||||
hasCount := 0
|
||||
for _, role := range this.GetUserRoleList(user.UID) {
|
||||
if role.SID == sid {
|
||||
hasCount++
|
||||
}
|
||||
}
|
||||
|
||||
const MaxRoleSameServer = 2 //同一账号单服最大角色数
|
||||
if hasCount >= MaxRoleSameServer && !user.Super {
|
||||
log.KV("uid", user.UID).KV("sid", sid).KV("hasCount", hasCount).WarnStack(1, "has too many role")
|
||||
user.LastLoginRID = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
newRole := model.NewRole(this.login, user.UID, rid, sid, ip, user.ABTest)
|
||||
newRole.Update()
|
||||
|
||||
user.Roles[newRole.RID] = true
|
||||
user.Update()
|
||||
|
||||
this.roles[newRole.RID] = newRole
|
||||
log.KV("passport", passport).KV("ptype", ptype).KV("sid", sid).KV("rid", newRole.RID).KV("uid", user.UID).InfoStack(1, "newrole")
|
||||
return newRole
|
||||
}
|
||||
|
||||
// 封号/解封
|
||||
func (this *UserManager) UpdateUserBan(uid int64, deadline, bancode int64) bool {
|
||||
user := this.users[uid]
|
||||
tools.AssertTrue(user != nil, "uid=%v not find", uid)
|
||||
user.Ban = deadline
|
||||
user.BanCode = bancode
|
||||
user.Update()
|
||||
log.KV("uid", uid).KV("deadline", deadline).Info("UpdateUserBan success")
|
||||
return true
|
||||
}
|
||||
|
||||
// 禁言/解禁
|
||||
func (this *UserManager) UpdateUserMute(uid int64, deadline int64) bool {
|
||||
user := this.users[uid]
|
||||
if user == nil {
|
||||
log.KV("uid", uid).Warn("uid not find")
|
||||
return false
|
||||
}
|
||||
|
||||
user.Mute = deadline
|
||||
user.Update()
|
||||
log.KV("uid", uid).KV("deadline", deadline).Info("UpdateUserMute success")
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *UserManager) UpdateUserSuper(uid int64, super bool) bool {
|
||||
user := this.users[uid]
|
||||
tools.AssertTrue(user != nil, "uid=%v not find", uid)
|
||||
user.Super = super
|
||||
user.Update()
|
||||
log.KV("uid", uid).KV("super", super).Info("UpdateUserSuper success")
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *UserManager) UpdateUserWhite(uid int64, white bool) {
|
||||
user := this.users[uid]
|
||||
tools.AssertTrue(user != nil, "uid=%v not find", uid)
|
||||
user.White = white
|
||||
user.Update()
|
||||
log.KV("uid", uid).KV("white", white).Info("UpdateUserWhite success")
|
||||
}
|
||||
|
||||
// todo 没有区分Android/ios
|
||||
func (this *UserManager) UpdateAudit(version string) {
|
||||
mp := sync.Map{}
|
||||
for _, i := range strings.Split(version, "|") {
|
||||
if len(i) > 0 {
|
||||
mp.Store(i, true)
|
||||
}
|
||||
}
|
||||
this.auditVersion = mp
|
||||
return
|
||||
}
|
||||
|
||||
func (this *UserManager) IsAudit(version string) bool {
|
||||
_, audit := this.auditVersion.Load(version)
|
||||
return audit
|
||||
}
|
||||
|
||||
func (this *UserManager) GetSID(rids []int64) []int32 {
|
||||
sids := make([]int32, 0)
|
||||
for _, rid := range rids {
|
||||
role := this.roles[rid]
|
||||
if role != nil {
|
||||
sids = append(sids, role.SID)
|
||||
} else {
|
||||
sids = append(sids, -1)
|
||||
}
|
||||
}
|
||||
return sids
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
package mgr_user
|
||||
|
||||
import "math/rand"
|
||||
|
||||
const period = 1000000 //7位
|
||||
const array = 100
|
||||
|
||||
func NewRIDCreator(lsid int32) *RIDCreator {
|
||||
creator := &RIDCreator{sids: make(map[int32]int64, 1024)}
|
||||
for rid := int64(lsid * period); rid < int64(lsid*period*10); rid++ {
|
||||
idx := rid % array
|
||||
if creator.ids[idx] == nil {
|
||||
creator.ids[idx] = make(map[int64]bool)
|
||||
}
|
||||
creator.ids[idx][rid] = true
|
||||
}
|
||||
return creator
|
||||
}
|
||||
|
||||
type RIDCreator struct {
|
||||
ids [array]map[int64]bool
|
||||
sids map[int32]int64
|
||||
}
|
||||
|
||||
func (this *RIDCreator) Add(rid int64) {
|
||||
idx := rid % array
|
||||
if this.ids[idx] != nil {
|
||||
delete(this.ids[idx], rid)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *RIDCreator) ID(sid int32) int64 {
|
||||
for {
|
||||
idx := rand.Intn(array)
|
||||
for rid := range this.ids[idx] {
|
||||
if this.sids[sid]%10 == rid%10 {
|
||||
this.sids[sid]++
|
||||
this.Add(rid)
|
||||
return rid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package login
|
||||
|
||||
func (s *Login) initAPI() {
|
||||
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"app/internal/service"
|
||||
"core/abtime"
|
||||
"core/ormdb"
|
||||
)
|
||||
|
||||
type GameServer struct {
|
||||
ormdb.DBObjBase `xorm:"extends"`
|
||||
ServerId int32 `xorm:"unique index"` //服务器Id
|
||||
ServerName string //服务器名字
|
||||
MaxRoleNum int32 //最大角色数
|
||||
Status service.GameServerStatus //服务器状态
|
||||
Recommend bool //是否推荐
|
||||
MaintainDeadline int64 //维护结束时间
|
||||
|
||||
Hearbeat int64 //心跳
|
||||
OnlineNum int32 //当前在线
|
||||
RoleNum int32 //注册数
|
||||
}
|
||||
|
||||
func NewGameServer(saver ormdb.IQueSaver, sid int32) *GameServer {
|
||||
result := &GameServer{ServerId: sid}
|
||||
result.OnNewObj(saver, result)
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *GameServer) IsAlive() bool {
|
||||
//const AliveHeart = 30 //x秒未收到心跳则表示失联
|
||||
//return abtime.Now().Unix()-this.Hearbeat < AliveHeart
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *GameServer) CanNewRole(isWhite bool) bool {
|
||||
if isWhite {
|
||||
return this.IsAlive() && this.Status >= service.StatusMaintain
|
||||
}
|
||||
return this.RoleNum < this.MaxRoleNum && this.IsAlive() && this.Status >= service.StatusOpen
|
||||
}
|
||||
|
||||
func (this *GameServer) Maintain() int64 {
|
||||
if this.Status == service.StatusMaintain {
|
||||
return this.MaintainDeadline
|
||||
} else if this.Status == service.StatusClose {
|
||||
return abtime.Now().Unix() + 8*3600
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"core/ormdb"
|
||||
)
|
||||
|
||||
// Passport 第三方登录账号
|
||||
type Passport struct {
|
||||
ormdb.DBObjBase `xorm:"extends"`
|
||||
Type string //账号类型
|
||||
PID string `xorm:"index"` //账号ID
|
||||
UID int64 `xorm:"index"` //游戏内账号ID
|
||||
CreateIP string //绑定时的客户端IP
|
||||
}
|
||||
|
||||
func NewPassport(saver ormdb.IQueSaver, uid int64, pid, ptype, ip string) *Passport {
|
||||
result := &Passport{
|
||||
Type: ptype,
|
||||
PID: pid,
|
||||
UID: uid,
|
||||
CreateIP: ip,
|
||||
}
|
||||
result.OnNewObj(saver, result)
|
||||
return result
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"core/ormdb"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Role 单个服内角色
|
||||
type Role struct {
|
||||
ormdb.DBObjBase `xorm:"extends"`
|
||||
RID int64 `xorm:"unique index"` //角色Id
|
||||
UID int64 `xorm:"index"` //游戏内账号ID
|
||||
SID int32 //角色所在服
|
||||
Icon string //头像
|
||||
Name string `xorm:"index"` //角色名
|
||||
League string //联盟短名字
|
||||
Power int64 //战力
|
||||
TownhallLv int32 //主城等级
|
||||
LastLogin int64 //最近一次登录时间
|
||||
CreateIP string //创建IP
|
||||
ABTest string //ab测试
|
||||
}
|
||||
|
||||
func NewRole(saver ormdb.IQueSaver, uid, rid int64, sid int32, ip, abtest string) *Role {
|
||||
result := &Role{
|
||||
RID: rid,
|
||||
UID: uid,
|
||||
SID: sid,
|
||||
CreateIP: ip,
|
||||
ABTest: abtest,
|
||||
}
|
||||
result.Name = fmt.Sprintf("Player%d", result.RID)
|
||||
result.OnNewObj(saver, result)
|
||||
return result
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"core/abtime"
|
||||
"core/ormdb"
|
||||
)
|
||||
|
||||
// 游戏内玩家
|
||||
type GameUser struct {
|
||||
ormdb.DBObjBase `xorm:"extends"`
|
||||
UID int64 `xorm:"unique index"` //游戏内账号ID
|
||||
|
||||
Roles map[int64]bool //RID=>Role 一个玩家可以拥有多个角色(包含已删除RID)
|
||||
LastLogin int64 //最近一次登录时间
|
||||
LastLoginRID int64 //最近一次登录RID
|
||||
Mute int64 //禁言时间截止
|
||||
Ban int64 //封号时间截止
|
||||
BanCode int64 //封号原因
|
||||
Super bool //是否是超级玩家(GM)
|
||||
White bool //是否是白名单玩家
|
||||
ABTest string //ab测试
|
||||
PackageCode string //客户端包名
|
||||
CreateIP string //绑定时的客户端IP
|
||||
IsNew bool //是否是新账号
|
||||
LastSession string `json:"-" xorm:"-"` //最近一次登录Session
|
||||
}
|
||||
|
||||
func NewUser(saver ormdb.IQueSaver, uid int64, ip string, abtest string) *GameUser {
|
||||
result := &GameUser{
|
||||
UID: uid,
|
||||
Ban: 0,
|
||||
Mute: 0,
|
||||
Super: false,
|
||||
Roles: map[int64]bool{},
|
||||
LastLogin: abtime.Now().Unix(),
|
||||
CreateIP: ip,
|
||||
ABTest: abtest,
|
||||
IsNew: true,
|
||||
}
|
||||
result.OnNewObj(saver, result)
|
||||
return result
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
HasLogin bool
|
||||
|
||||
RID int64
|
||||
UID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func NewRole() *Role {
|
||||
return &Role{}
|
||||
}
|
||||
|
||||
func (role *Role) SyncLoginResult(msg *message.LoginResult) {
|
||||
if msg.Result != message.MSG_RESULT_SUCCESS {
|
||||
return
|
||||
}
|
||||
role.HasLogin = true
|
||||
role.RID = msg.Role
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"app/internal/iniconfig"
|
||||
"app/internal/msg_util"
|
||||
"app/servers/internal/app_tools"
|
||||
"core/log"
|
||||
"core/network"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func NewClient(conf *iniconfig.Config, account string, parser *msg_util.ProtoParser, initState IState, isCycle bool) *Client {
|
||||
c := &Client{
|
||||
conf: conf,
|
||||
paymentAddr: conf.String("payment"),
|
||||
loginAddr: conf.String("login"),
|
||||
goatLoginKey: conf.String("goat_key"),
|
||||
account: account,
|
||||
passport_type: conf.MustString("passport_type", app_tools.PassportTypeUUID),
|
||||
msgCh: make(chan proto.Message, 64),
|
||||
parser: parser,
|
||||
isCycle: isCycle,
|
||||
}
|
||||
c.fsm = NewFsm(c, initState)
|
||||
log.KV("account", account).Info("robot start")
|
||||
return c
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
conf *iniconfig.Config
|
||||
fsm *Fsm
|
||||
|
||||
parser *msg_util.ProtoParser
|
||||
msgCh chan proto.Message
|
||||
gameConn network.INetClient
|
||||
chatConn network.INetClient
|
||||
|
||||
paymentAddr string
|
||||
loginAddr string
|
||||
gameAddr string
|
||||
goatLoginKey string
|
||||
|
||||
account string
|
||||
passport_type string
|
||||
sid int32
|
||||
uid int64
|
||||
rid int64
|
||||
isCycle bool
|
||||
}
|
||||
|
||||
func (this *Client) Config() *iniconfig.Config { return this.conf }
|
||||
func (this *Client) GoatKey() string { return this.goatLoginKey }
|
||||
func (this *Client) FixState() string { return this.conf.MustString("state_mode", "") }
|
||||
func (this *Client) Parser() *msg_util.ProtoParser { return this.parser }
|
||||
func (this *Client) PaymentAddr() string { return this.paymentAddr }
|
||||
func (this *Client) LoginAddr() string { return this.loginAddr }
|
||||
func (this *Client) GameAddr() string { return this.gameAddr }
|
||||
func (this *Client) Account() string { return this.account }
|
||||
func (this *Client) PassportType() string { return this.passport_type }
|
||||
func (this *Client) SID() int32 { return this.sid }
|
||||
func (this *Client) UpdateLoginInfo(gameAddr string, gameConn network.INetClient, sid int32, uid int64, rid int64) {
|
||||
this.gameAddr = gameAddr
|
||||
this.rid = rid
|
||||
this.uid = uid
|
||||
this.sid = sid
|
||||
this.gameConn = gameConn
|
||||
}
|
||||
|
||||
func (this *Client) recvMsg(pbmsg proto.Message) { this.msgCh <- pbmsg }
|
||||
|
||||
func (this *Client) Send2Game(msg proto.Message) {
|
||||
if conn := this.gameConn; conn != nil {
|
||||
conn.SendMsg(msg)
|
||||
}
|
||||
}
|
||||
func (this *Client) Send2Chat(msg proto.Message) {
|
||||
if conn := this.chatConn; conn != nil {
|
||||
conn.SendMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Client) Stop() {
|
||||
if conn := this.gameConn; conn != nil {
|
||||
this.gameConn = nil
|
||||
conn.Stop()
|
||||
}
|
||||
|
||||
if conn := this.chatConn; conn != nil {
|
||||
this.chatConn = nil
|
||||
conn.Stop()
|
||||
}
|
||||
this.fsm.Stop()
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/internal/msg_util"
|
||||
"app/servers/robot/data"
|
||||
"core/abtime"
|
||||
"core/goroutine"
|
||||
"core/log"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewFsm(c *Client, initState IState) *Fsm {
|
||||
f := &Fsm{
|
||||
role: data.NewRole(),
|
||||
states: make(map[reflect.Type]IState),
|
||||
initState: initState,
|
||||
msgDispatcher: make(map[string][]StateHandler),
|
||||
client: c,
|
||||
closec: make(chan struct{}),
|
||||
}
|
||||
|
||||
for ptrType := range _states {
|
||||
f.regist(ptrType)
|
||||
}
|
||||
|
||||
goroutine.GoLogic(func() {
|
||||
f.RegistMsgHandler((*message.Pong)(nil), f.handPong)
|
||||
f.SwtichToState(f.initState)
|
||||
f.start(c.msgCh)
|
||||
}, nil)
|
||||
return f
|
||||
}
|
||||
|
||||
type Fsm struct {
|
||||
role *data.Role
|
||||
curState IState
|
||||
initState IState
|
||||
states map[reflect.Type]IState //stateT->state
|
||||
msgDispatcher map[string][]StateHandler //msgName->handlers
|
||||
client *Client
|
||||
closec chan struct{}
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (this *Fsm) regist(stateType reflect.Type) {
|
||||
statePtr := reflect.New(stateType.Elem()).Interface().(IState)
|
||||
this.states[stateType] = statePtr
|
||||
statePtr.init(this)
|
||||
statePtr.Init()
|
||||
}
|
||||
|
||||
func (this *Fsm) start(msgCh <-chan proto.Message) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-this.closec:
|
||||
break loop
|
||||
case <-ticker.C:
|
||||
goroutine.Try(this.update, nil)
|
||||
case msg := <-msgCh:
|
||||
goroutine.Try(func() { this.dispatchMsg(msg) }, nil)
|
||||
}
|
||||
}
|
||||
this.Stop()
|
||||
}
|
||||
|
||||
func (this *Fsm) dispatchMsg(msg proto.Message) {
|
||||
if handlers, ok := this.msgDispatcher["*"]; ok {
|
||||
for _, handler := range handlers {
|
||||
handler(msg)
|
||||
}
|
||||
}
|
||||
|
||||
msgName := msg_util.MsgName(msg)
|
||||
if handlers, ok := this.msgDispatcher[msgName]; ok {
|
||||
for _, handler := range handlers {
|
||||
handler(msg)
|
||||
}
|
||||
} else {
|
||||
log.KV("msg_name", msg_util.MsgName(msg)).Debug("not hand msg")
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Fsm) update() {
|
||||
this.curState.OnUpdate()
|
||||
//log.KV("state", reflect.TypeOf(this.curState).Elem().Name()).Debug("fsm state update")
|
||||
this.client.Send2Game(&message.Ping{ClientTime: abtime.Now().UnixNano()})
|
||||
}
|
||||
|
||||
func (this *Fsm) SwtichToState(statePtr IState, params ...interface{}) {
|
||||
stateType := reflect.TypeOf(statePtr)
|
||||
state, ok := this.states[stateType]
|
||||
if !ok {
|
||||
log.KV("state", stateType.Elem().Name()).Error("SwtichToState not regist")
|
||||
return
|
||||
}
|
||||
if this.curState != nil {
|
||||
this.curState.OnExit()
|
||||
}
|
||||
this.curState = state
|
||||
state.OnEnter(params...)
|
||||
log.KV("account", this.client.account).KV("state", stateType.Elem().Name()).Info("SwtichToState")
|
||||
}
|
||||
|
||||
func (this *Fsm) Stop() {
|
||||
this.closeOnce.Do(func() { close(this.closec) })
|
||||
}
|
||||
|
||||
func (this *Fsm) RegistMsgHandler(msg interface{}, hander StateHandler) {
|
||||
msgName := msg_util.MsgName(msg)
|
||||
this.msgDispatcher[msgName] = append(this.msgDispatcher[msgName], hander)
|
||||
}
|
||||
|
||||
func (this *Fsm) GetState(statePtr IState) IState {
|
||||
stateType := reflect.TypeOf(statePtr)
|
||||
return this.states[stateType]
|
||||
}
|
||||
|
||||
func (this *Fsm) handPong(msg proto.Message) {
|
||||
//resp := msg.(*message.S2CPong)
|
||||
//cost := abtime.Now().UnixNano() - resp.ClientTime
|
||||
//log.KV("rtt", cost).Debug("StateHome handPingResult")
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"core/log"
|
||||
"core/network"
|
||||
"fmt"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StateHandler func(msg proto.Message)
|
||||
|
||||
func NewGameHandler(client *Client) *GameHandler { return &GameHandler{client: client} }
|
||||
|
||||
type GameHandler struct {
|
||||
network.BaseNetHandler
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (this *GameHandler) OnSessionCreated() {}
|
||||
func (this *GameHandler) OnSessionClosed() {
|
||||
log.KV("account", this.client.account).Info("robot stop")
|
||||
this.client.Stop()
|
||||
if !this.client.isCycle {
|
||||
time.Sleep(time.Second * 2)
|
||||
NewClient(this.client.conf, this.client.account, this.client.parser, this.client.fsm.initState, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GameHandler) OnRecv(msgId int32, msg interface{}) {
|
||||
if res, ok := msg.(*message.NotifyKickOut); ok {
|
||||
log.KV("account", this.client.account).KV("reason", res.Reason).Warn("client kick out")
|
||||
this.client.Stop()
|
||||
return
|
||||
}
|
||||
if res, ok := msg.(*message.MessageResult); ok {
|
||||
if reqName, ok2 := this.client.Parser().MsgIdToName(res.ProtoId); ok2 {
|
||||
if res.Data != nil {
|
||||
respName := fmt.Sprintf("%sResult", reqName)
|
||||
if msgData, ok3 := this.client.Parser().UnmarshalByName(respName, res.Data); ok3 {
|
||||
this.client.recvMsg(msgData)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
this.client.recvMsg(msg.(proto.Message))
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/servers/internal/worldmap"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func RandomPick(count int) int {
|
||||
indexList := make([]int, count)
|
||||
for i := 0; i < count; i++ {
|
||||
indexList[i] = i
|
||||
}
|
||||
Shuffle(indexList)
|
||||
return indexList[0]
|
||||
}
|
||||
func RandomSample(count int, pickCount int) []int {
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
if pickCount > count {
|
||||
pickCount = count
|
||||
}
|
||||
indexList := make([]int, count)
|
||||
for i := 0; i < count; i++ {
|
||||
indexList[i] = i
|
||||
}
|
||||
Shuffle(indexList)
|
||||
return indexList[:pickCount]
|
||||
}
|
||||
func Shuffle(indexList []int) {
|
||||
rand.Shuffle(len(indexList), func(i, j int) { indexList[i], indexList[j] = indexList[j], indexList[i] })
|
||||
}
|
||||
|
||||
func RandPos() *message.Vector {
|
||||
return &message.Vector{
|
||||
X: float64(rand.Intn(worldmap.WORLD_MAP_SIZE)),
|
||||
Y: float64(rand.Intn(worldmap.WORLD_MAP_SIZE)),
|
||||
}
|
||||
}
|
||||
func RandPosValue() int32 {
|
||||
return int32(rand.Intn(worldmap.WORLD_MAP_SIZE))
|
||||
}
|
||||
func RandRadius() float64 {
|
||||
return rand.Float64() * 30 //[0,30)
|
||||
}
|
||||
|
||||
func Roll(chance float64) bool {
|
||||
return rand.Float64() < chance
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"app/servers/robot/data"
|
||||
"core/goroutine"
|
||||
"core/tools"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IState interface {
|
||||
init(fsm *Fsm)
|
||||
Init()
|
||||
|
||||
OnEnter(params ...interface{})
|
||||
OnExit()
|
||||
OnUpdate()
|
||||
}
|
||||
|
||||
type BaseState struct {
|
||||
role *data.Role
|
||||
fsm *Fsm
|
||||
client *Client
|
||||
sendF []func() //待执行队列
|
||||
}
|
||||
|
||||
func (this *BaseState) Role() *data.Role { return this.role }
|
||||
func (this *BaseState) Client() *Client { return this.client }
|
||||
|
||||
func (this *BaseState) init(fsm *Fsm) {
|
||||
this.role = fsm.role
|
||||
this.fsm = fsm
|
||||
this.client = fsm.client
|
||||
}
|
||||
|
||||
func (this *BaseState) OnUpdate() {
|
||||
if len(this.sendF) <= 0 {
|
||||
this.SwtichToState(this.fsm.initState, nil)
|
||||
} else {
|
||||
goroutine.Try(this.sendF[0], nil)
|
||||
this.sendF = this.sendF[1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (this *BaseState) AppendFunc(fns ...func()) {
|
||||
for _, fn := range fns {
|
||||
this.sendF = append(this.sendF, fn)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *BaseState) GetState(statePtr IState) IState {
|
||||
return this.fsm.GetState(statePtr)
|
||||
}
|
||||
|
||||
func (this *BaseState) SwtichToState(statePtr IState, params ...interface{}) {
|
||||
this.fsm.SwtichToState(statePtr, params...)
|
||||
}
|
||||
|
||||
func (this *BaseState) Send2Game(msg proto.Message) {
|
||||
this.client.Send2Game(msg)
|
||||
}
|
||||
|
||||
func (this *BaseState) Send2Chat(msg proto.Message) {
|
||||
this.client.Send2Chat(msg)
|
||||
}
|
||||
|
||||
func (this *BaseState) RegistMsgHandler(msg interface{}, hander StateHandler) {
|
||||
this.fsm.RegistMsgHandler(msg, hander)
|
||||
}
|
||||
func (this *BaseState) Void(msg proto.Message) {}
|
||||
|
||||
var _states = map[reflect.Type]IState{}
|
||||
var _stateNames = map[string]IState{}
|
||||
|
||||
func RegistState(statePtr IState) bool {
|
||||
stateType := reflect.TypeOf(statePtr)
|
||||
tools.AssertTrue(stateType.Kind() == reflect.Ptr, stateType.Name())
|
||||
|
||||
name := strings.ToLower(stateType.Elem().Name())
|
||||
|
||||
_, ok := _stateNames[name]
|
||||
tools.AssertTrue(!ok, name)
|
||||
|
||||
_stateNames[name] = statePtr
|
||||
_states[stateType] = statePtr
|
||||
return false
|
||||
}
|
||||
|
||||
func FindState(name string) IState {
|
||||
if s, ok := _stateNames[strings.ToLower(name)]; ok {
|
||||
return s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,114 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"core/log"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
)
|
||||
|
||||
const (
|
||||
WEB_ADDR = "192.168.0.37:8100"
|
||||
WEB_USER = "admin"
|
||||
WEB_PWD = "admin123"
|
||||
)
|
||||
|
||||
type WebSession struct {
|
||||
addr string
|
||||
user string
|
||||
pwd string
|
||||
client *http.Client
|
||||
token string
|
||||
}
|
||||
type CommonResp struct {
|
||||
Code int "json:code"
|
||||
}
|
||||
type LoginResp struct {
|
||||
Code int "json:code"
|
||||
Msg LoginRespMsg "json:msg"
|
||||
}
|
||||
type LoginRespMsg struct {
|
||||
Token string "json:token"
|
||||
}
|
||||
|
||||
var session *WebSession
|
||||
|
||||
func getSession() *WebSession {
|
||||
if session == nil {
|
||||
jar, _ := cookiejar.New(nil)
|
||||
session = &WebSession{
|
||||
WEB_ADDR, WEB_USER, WEB_PWD, &http.Client{Jar: jar}, "",
|
||||
}
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// 返回是否登录成功
|
||||
func (s *WebSession) login() bool {
|
||||
values := map[string]string{"account": s.user, "pwd": s.pwd}
|
||||
resp := s.cmd("/api/login", values)
|
||||
if resp == nil {
|
||||
return false
|
||||
}
|
||||
ret := &LoginResp{}
|
||||
err := json.Unmarshal(resp, ret)
|
||||
if err != nil {
|
||||
s.token = ret.Msg.Token
|
||||
return ret.Code == 0
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func (s *WebSession) cmd(cmd string, values interface{}) []byte {
|
||||
jsonValue, e1 := json.Marshal(values)
|
||||
if e1 != nil {
|
||||
log.KV("err", e1).Warn("json marshal err")
|
||||
return nil
|
||||
}
|
||||
req, e2 := http.NewRequest("POST", fmt.Sprintf("http://%s%s", s.addr, cmd), bytes.NewBuffer(jsonValue))
|
||||
if e2 != nil {
|
||||
log.KV("err", e2).Warn("http request create err")
|
||||
return nil
|
||||
}
|
||||
req.Header.Set("accesstoken", s.token)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, e3 := s.client.Do(req)
|
||||
if e3 != nil {
|
||||
log.KV("err", e3).Warn("http request err")
|
||||
return nil
|
||||
}
|
||||
respData, e4 := ioutil.ReadAll(resp.Body)
|
||||
if e4 != nil {
|
||||
log.KV("err", e4).Warn("http read response err")
|
||||
return nil
|
||||
}
|
||||
e5 := resp.Body.Close()
|
||||
if e5 != nil {
|
||||
log.KV("err", e5).Warn("http response io close err")
|
||||
return nil
|
||||
}
|
||||
respJson := &CommonResp{}
|
||||
e6 := json.Unmarshal(respData, respJson)
|
||||
if e6 != nil {
|
||||
log.KV("err", e6).Warn("json unmarshal io err")
|
||||
return nil
|
||||
}
|
||||
if respJson.Code == 1002 { //未登录
|
||||
isLoginOK := s.login()
|
||||
if isLoginOK {
|
||||
return s.cmd(cmd, values)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return respData
|
||||
}
|
||||
|
||||
// WebCmd 外部接口
|
||||
func WebCmd(cmd string, values interface{}) {
|
||||
se := getSession()
|
||||
se.cmd(cmd, values)
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package states
|
||||
|
||||
import (
|
||||
"app/servers/robot/internal"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var allStates = [...]internal.IState{
|
||||
(*StateHome)(nil),
|
||||
(*StateLogin)(nil),
|
||||
(*StateDemo)(nil),
|
||||
}
|
||||
|
||||
var _initOnce sync.Once
|
||||
|
||||
func InitStates() {
|
||||
_initOnce.Do(func() {
|
||||
for _, state := range allStates {
|
||||
internal.RegistState(state)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1,179 +0,0 @@
|
||||
package states
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/servers/robot/internal"
|
||||
"golang.org/x/exp/maps"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type StateDemo struct {
|
||||
internal.BaseState
|
||||
entityMap map[int64]*message.MapEntity
|
||||
entityMapSelf map[int64]*message.MapEntity
|
||||
gridListenMap map[int32]bool
|
||||
}
|
||||
|
||||
func (this *StateDemo) Init() {
|
||||
this.entityMap = make(map[int64]*message.MapEntity)
|
||||
this.entityMapSelf = make(map[int64]*message.MapEntity)
|
||||
this.gridListenMap = make(map[int32]bool)
|
||||
this.RegistMsgHandler((*message.NotifyMapEntityList)(nil), this.handNotifyMapEntityList)
|
||||
this.RegistMsgHandler((*message.MapLookAtResult)(nil), this.handMapLookAtResult)
|
||||
this.RegistMsgHandler((*message.NotifyMapBattleInfo)(nil), this.Void)
|
||||
this.RegistMsgHandler((*message.NotifyMapMoveInfo)(nil), this.Void)
|
||||
this.RegistMsgHandler((*message.NotifyMapHpInfo)(nil), this.Void)
|
||||
}
|
||||
|
||||
func (this *StateDemo) OnEnter(params ...interface{}) {
|
||||
this.AppendFunc(
|
||||
this.TestCreateMapEntity,
|
||||
this.MapEntityMove,
|
||||
this.MapEntityMoveTo,
|
||||
//this.MapEntityStop,
|
||||
//this.MapEntityReturn,
|
||||
this.MapLookAt,
|
||||
//this.MapRemoveLookAt,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func (this *StateDemo) OnExit() {}
|
||||
|
||||
func (this *StateDemo) TestCreateMapEntity() {
|
||||
if internal.Roll(0.8) {
|
||||
return
|
||||
}
|
||||
this.Send2Game(&message.TestCreateMapEntity{
|
||||
Pos: internal.RandPos(),
|
||||
})
|
||||
}
|
||||
func (this *StateDemo) MapEntityMove() {
|
||||
if eid := this.PickEntitySelfIdle(); eid != 0 {
|
||||
this.Send2Game(&message.MapEntityMove{
|
||||
EID: eid,
|
||||
Pos: internal.RandPos(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateDemo) MapEntityMoveTo() {
|
||||
if eid := this.PickEntitySelfIdle(); eid != 0 {
|
||||
if eidTarget := this.PickEntityOther(); eidTarget != 0 {
|
||||
this.Send2Game(&message.MapEntityMoveTo{
|
||||
EID: eid,
|
||||
TargetEID: eidTarget,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
func (this *StateDemo) MapEntityStop() {
|
||||
if eid := this.PickEntitySelf(); eid != 0 {
|
||||
this.Send2Game(&message.MapEntityStop{
|
||||
EID: eid,
|
||||
})
|
||||
}
|
||||
}
|
||||
func (this *StateDemo) MapEntityReturn() {
|
||||
if eid := this.PickEntitySelf(); eid != 0 {
|
||||
this.Send2Game(&message.MapEntityReturn{
|
||||
EID: eid,
|
||||
})
|
||||
}
|
||||
}
|
||||
func (this *StateDemo) MapLookAt() {
|
||||
maps.Clear(this.entityMapSelf)
|
||||
maps.Clear(this.entityMap)
|
||||
this.Send2Game(&message.MapLookAt{
|
||||
PosX: internal.RandPosValue(),
|
||||
PosY: internal.RandPosValue(),
|
||||
Width: 200,
|
||||
Height: 100,
|
||||
})
|
||||
}
|
||||
func (this *StateDemo) MapRemoveLookAt() {
|
||||
maps.Clear(this.entityMapSelf)
|
||||
maps.Clear(this.entityMap)
|
||||
if internal.Roll(0.2) {
|
||||
this.Send2Game(&message.MapRemoveLookAt{})
|
||||
}
|
||||
}
|
||||
func (this *StateDemo) PickEntitySelfIdle() int64 {
|
||||
var eidList []int64
|
||||
for _, entity := range this.entityMapSelf {
|
||||
if entity.State == message.MAP_ENTITY_STATE_IDLE {
|
||||
eidList = append(eidList, entity.EID)
|
||||
}
|
||||
}
|
||||
if len(eidList) > 0 {
|
||||
pickIndex := internal.RandomPick(len(eidList))
|
||||
return eidList[pickIndex]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (this *StateDemo) PickEntitySelf() int64 {
|
||||
var eidList []int64
|
||||
for _, entity := range this.entityMapSelf {
|
||||
eidList = append(eidList, entity.EID)
|
||||
}
|
||||
if len(eidList) > 0 {
|
||||
pickIndex := internal.RandomPick(len(eidList))
|
||||
return eidList[pickIndex]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *StateDemo) PickEntityOther() int64 {
|
||||
var eidList []int64
|
||||
for _, entity := range this.entityMap {
|
||||
if entity.RID != this.Role().RID {
|
||||
eidList = append(eidList, entity.EID)
|
||||
}
|
||||
}
|
||||
if len(eidList) > 0 {
|
||||
pickIndex := internal.RandomPick(len(eidList))
|
||||
return eidList[pickIndex]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *StateDemo) handTestCreateMapEntityResult(msg proto.Message) {
|
||||
//resp := msg.(*message.TestCreateMapEntityResult)
|
||||
}
|
||||
func (this *StateDemo) handMapEntityMoveResult(msg proto.Message) {
|
||||
//resp := msg.(*message.MapEntityMoveResult)
|
||||
}
|
||||
func (this *StateDemo) handNotifyMapEntityList(msg proto.Message) {
|
||||
resp := msg.(*message.NotifyMapEntityList)
|
||||
for _, entity := range resp.MapEntityList {
|
||||
this.entityMap[entity.EID] = entity
|
||||
if this.Role().RID == entity.RID {
|
||||
this.entityMapSelf[entity.EID] = entity
|
||||
}
|
||||
}
|
||||
for _, eid := range resp.MapEntityDelList {
|
||||
this.delEntity(eid)
|
||||
}
|
||||
for _, cross := range resp.MapEntityCrossList {
|
||||
if _, ok := this.gridListenMap[cross.GridId]; !ok {
|
||||
this.delEntity(cross.EID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateDemo) handMapLookAtResult(msg proto.Message) {
|
||||
resp := msg.(*message.MapLookAtResult)
|
||||
maps.Clear(this.gridListenMap)
|
||||
for _, gridId := range resp.GridIdList {
|
||||
this.gridListenMap[gridId] = true
|
||||
}
|
||||
for eid, entity := range this.entityMap {
|
||||
if _, ok := this.gridListenMap[entity.GridId]; !ok {
|
||||
this.delEntity(eid)
|
||||
}
|
||||
}
|
||||
}
|
||||
func (this *StateDemo) delEntity(eid int64) {
|
||||
delete(this.entityMap, eid)
|
||||
delete(this.entityMapSelf, eid)
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
package states
|
||||
|
||||
import (
|
||||
"app/internal/message"
|
||||
"app/servers/robot/internal"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type StateHome struct {
|
||||
internal.BaseState
|
||||
hasLogin bool
|
||||
}
|
||||
|
||||
func (this *StateHome) Init() {
|
||||
this.RegistMsgHandler("*", this.handAll)
|
||||
}
|
||||
|
||||
func (this *StateHome) OnEnter(params ...interface{}) {
|
||||
if len(params) > 0 {
|
||||
if _, ok := params[0].(*StateLogin); ok {
|
||||
this.hasLogin = true
|
||||
}
|
||||
}
|
||||
if !this.hasLogin {
|
||||
this.SwtichToState((*StateLogin)(nil))
|
||||
}
|
||||
}
|
||||
func (this *StateHome) OnExit() {}
|
||||
|
||||
func (this *StateHome) OnUpdate() {
|
||||
name := this.Client().FixState()
|
||||
if state := internal.FindState(name); state != nil {
|
||||
this.SwtichToState(state, nil)
|
||||
} else {
|
||||
this.randState()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateHome) randState() {
|
||||
state := allStates[rand.Intn(len(allStates))]
|
||||
_, login := state.(*StateLogin)
|
||||
_, home := state.(*StateHome)
|
||||
if !login && !home {
|
||||
this.SwtichToState(state, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateHome) handAll(arg proto.Message) {
|
||||
switch msg := arg.(type) {
|
||||
case *message.LoginResult:
|
||||
this.Role().SyncLoginResult(msg)
|
||||
}
|
||||
}
|
||||
@ -1,164 +0,0 @@
|
||||
package states
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"app/internal/message"
|
||||
"app/internal/msg_util"
|
||||
"app/servers/robot/internal"
|
||||
"core/abtime"
|
||||
"core/log"
|
||||
"core/network"
|
||||
"core/tools"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type StateLogin struct {
|
||||
internal.BaseState
|
||||
ip string
|
||||
}
|
||||
|
||||
func (this *StateLogin) Init() {
|
||||
this.RegistMsgHandler((*message.LoginResult)(nil), this.handLoginResult)
|
||||
}
|
||||
|
||||
func (this *StateLogin) OnEnter(params ...interface{}) {
|
||||
if !this.Login() {
|
||||
time.Sleep(time.Second * 10)
|
||||
this.SwtichToState((*StateLogin)(nil), nil)
|
||||
}
|
||||
if this.ip == "" {
|
||||
this.ip = fmt.Sprintf("%d:%d:%d:%d", rand.Intn(255)+1, rand.Intn(255)+1, rand.Intn(255)+1, rand.Intn(255)+1)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateLogin) OnExit() {}
|
||||
func (this *StateLogin) OnUpdate() {}
|
||||
|
||||
func (this *StateLogin) Login() (ok bool) {
|
||||
type LoginReq struct {
|
||||
Passport string //账号
|
||||
PassportType string //账号类型
|
||||
OS string //操作系统
|
||||
Version string //客户端版本号
|
||||
RID int64 //角色ID(0=由服务器分配)
|
||||
Extra string //sdk额外数据
|
||||
ClientIP string //客户端IP
|
||||
}
|
||||
|
||||
type LoginResp struct {
|
||||
Code int32 //成功码
|
||||
RID int64 //玩家RID
|
||||
UID int64
|
||||
SID int32 //服务器Id
|
||||
GameServerAddr string //服务器ip:port
|
||||
Mute int64 //禁言截止时间
|
||||
Ban int64 //封号截止时间
|
||||
Super bool //是否GM账号
|
||||
Session string //登录session
|
||||
Timestamp int64 //登录时间
|
||||
MaintainTime int64 //维护结束时间
|
||||
}
|
||||
|
||||
req := &LoginReq{
|
||||
Passport: this.Client().Account(),
|
||||
PassportType: this.Client().PassportType(),
|
||||
OS: "Android",
|
||||
ClientIP: this.ip,
|
||||
Extra: this.loginExtra(this.Client().Account()),
|
||||
}
|
||||
|
||||
reqData, _ := json.Marshal(req)
|
||||
loginUrl := fmt.Sprintf("%s/login", this.Client().LoginAddr())
|
||||
respData, err := tools.HttpPost(loginUrl, reqData)
|
||||
if err != nil {
|
||||
log.KV("err", err).KV("url", loginUrl).KV("reqData", string(reqData)).KV("respData", string(respData)).Warn("login request")
|
||||
return
|
||||
}
|
||||
|
||||
resp := &LoginResp{}
|
||||
err = json.Unmarshal(respData, resp)
|
||||
if err != nil {
|
||||
log.KV("err", err).KV("resp", string(respData)).Warn("login resp json unmarshal failed")
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
log.KV("code", resp.Code).KV("resp", string(respData)).Warn("login failed")
|
||||
return
|
||||
}
|
||||
log.KV("account", this.Client().Account()).Info("StateLogin: login success")
|
||||
|
||||
tcpClient := network.NewTcpClient(resp.GameServerAddr,
|
||||
func() network.ICodec { return msg_util.NewProtoCodec(this.Client().Parser(), 0, false) },
|
||||
func() network.INetHandler { return internal.NewGameHandler(this.Client()) },
|
||||
)
|
||||
|
||||
if err := tcpClient.Connect(false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.Client().UpdateLoginInfo(resp.GameServerAddr, tcpClient, resp.SID, resp.UID, resp.RID)
|
||||
|
||||
this.Send2Game(&message.Login{
|
||||
Session: resp.Session,
|
||||
LoginTime: resp.Timestamp,
|
||||
RID: resp.RID,
|
||||
SID: resp.SID,
|
||||
UID: resp.UID,
|
||||
Mute: resp.Mute,
|
||||
Ban: resp.Ban,
|
||||
Super: resp.Super,
|
||||
OS: "Android",
|
||||
Language: "cn",
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *StateLogin) handLoginResult(msg proto.Message) {
|
||||
resp := msg.(*message.LoginResult)
|
||||
if resp.Result != message.MSG_RESULT_SUCCESS {
|
||||
log.KV("account", this.Client().Account()).KV("result", resp.Result).Warn("client login failed")
|
||||
time.Sleep(time.Second * 2)
|
||||
this.SwtichToState((*StateLogin)(nil), nil)
|
||||
} else {
|
||||
log.KV("account", this.Client().Account()).Info("handLoginResult")
|
||||
this.SwtichToState((*StateHome)(nil), this)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StateLogin) loginExtra(account string) string {
|
||||
type Req struct {
|
||||
//AliasID int `json:"aliasId"`
|
||||
//Nick string `json:"nick"`
|
||||
//Username string `json:"username"`
|
||||
//Avatar string `json:"avatar"`
|
||||
//Email string `json:"email"`
|
||||
UserID string `json:"userId"`
|
||||
//Create bool `json:"create"`
|
||||
//Reset bool `json:"reset"`
|
||||
//Bound bool `json:"bound"`
|
||||
//UserType string `json:"userType"`
|
||||
//Info interface{} `json:"info"`
|
||||
//Token string `json:"token"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Sign string `json:"sign"`
|
||||
}
|
||||
|
||||
param := &Req{
|
||||
UserID: account,
|
||||
Timestamp: tools.Itoa64(abtime.Now().Unix()),
|
||||
}
|
||||
|
||||
h := md5.New()
|
||||
h.Write([]byte(this.Client().GoatKey() + param.UserID + param.Timestamp))
|
||||
b := h.Sum(nil)
|
||||
param.Sign = hex.EncodeToString(b)
|
||||
data, _ := json.Marshal(param)
|
||||
return string(data)
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package fathers
|
||||
|
||||
import (
|
||||
"app/servers/internal/service_base"
|
||||
)
|
||||
|
||||
type IRole interface {
|
||||
service_base.IServiceBase
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package role
|
||||
|
||||
func (s *Role) initAPI() {
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package game_mgr
|
||||
|
||||
import (
|
||||
"app/service/main/message/pb"
|
||||
"app/service/main/msg_util"
|
||||
"app/service/main/user"
|
||||
"core/douyin"
|
||||
"core/network"
|
||||
)
|
||||
|
||||
var APP_TOKEN_MAP = map[string]string{
|
||||
"ttaef8d84531c975bb10": "123",
|
||||
}
|
||||
|
||||
type GameMgr struct {
|
||||
appMap map[string]douyin.IApp
|
||||
}
|
||||
|
||||
func NewGameMgr() *GameMgr {
|
||||
return &GameMgr{}
|
||||
}
|
||||
|
||||
func (s *GameMgr) Run() error {
|
||||
s.appMap = make(map[string]douyin.IApp)
|
||||
|
||||
//for appId, appSecret := range APP_TOKEN_MAP {
|
||||
// newApp := douyin.NewApp(appId, appSecret)
|
||||
// s.appMap[appId] = newApp
|
||||
// newApp.StartRefreshToken()
|
||||
//}
|
||||
|
||||
listener := network.NewTcpListener(
|
||||
":8888",
|
||||
s.newParser,
|
||||
s.newHandler)
|
||||
|
||||
err := listener.Listen()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *GameMgr) newParser() network.ICodec {
|
||||
return msg_util.NewProtoCodec(msg_util.NewProtoParser("message", "MSG_TYPE"), 1024*64, false)
|
||||
}
|
||||
|
||||
func (s *GameMgr) newHandler() network.INetHandler {
|
||||
return user.NewUser(s)
|
||||
}
|
||||
|
||||
func (s *GameMgr) Login(appId string, token string) (string, string, string, pb.ERROR_CODE) {
|
||||
app, ok := s.appMap[appId]
|
||||
if !ok {
|
||||
return "", "", "", pb.ERROR_CODE_INVALID_APPID
|
||||
}
|
||||
roomId, uid, nickName, err := app.GetRoomId(token)
|
||||
if err != nil {
|
||||
return "", "", "", pb.ERROR_CODE_INVALID_TOKEN
|
||||
}
|
||||
return roomId, uid, nickName, pb.ERROR_CODE_SUCCESS
|
||||
}
|
||||
|
||||
func (s *GameMgr) StartTask(appId string, roomId string, msgType string) pb.ERROR_CODE {
|
||||
app, ok := s.appMap[appId]
|
||||
if !ok {
|
||||
return pb.ERROR_CODE_INVALID_APPID
|
||||
}
|
||||
|
||||
_, err := app.StartTask(roomId, msgType)
|
||||
if err != nil {
|
||||
return pb.ERROR_CODE_FAIL
|
||||
}
|
||||
return pb.ERROR_CODE_SUCCESS
|
||||
}
|
||||
|
||||
func (s *GameMgr) StopTask(appId string, roomId string, msgType string) pb.ERROR_CODE {
|
||||
app, ok := s.appMap[appId]
|
||||
if !ok {
|
||||
return pb.ERROR_CODE_INVALID_APPID
|
||||
}
|
||||
|
||||
_, err := app.StopTask(roomId, msgType)
|
||||
if err != nil {
|
||||
return pb.ERROR_CODE_FAIL
|
||||
}
|
||||
return pb.ERROR_CODE_SUCCESS
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
package game_mgr
|
||||
@ -0,0 +1,9 @@
|
||||
package in_obj
|
||||
|
||||
import "app/service/main/message/pb"
|
||||
|
||||
type IGameMgr interface {
|
||||
Login(appId string, token string) (string, string, string, pb.ERROR_CODE)
|
||||
StartTask(appId string, roomId string, msgType string) pb.ERROR_CODE
|
||||
StopTask(appId string, roomId string, msgType string) pb.ERROR_CODE
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,304 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc (unknown)
|
||||
// source: msgtype.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
import proto "google.golang.org/protobuf/proto"
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type MSG_TYPE int32
|
||||
|
||||
const (
|
||||
MSG_TYPE__ERROR MSG_TYPE = 0 //Error
|
||||
MSG_TYPE__Login MSG_TYPE = 1 //Login
|
||||
MSG_TYPE__LoginResult MSG_TYPE = 2 //LoginResult
|
||||
MSG_TYPE__PlayStart MSG_TYPE = 3 //PlayStart
|
||||
MSG_TYPE__PlayStartResult MSG_TYPE = 4 //PlayStartResult
|
||||
MSG_TYPE__PlayEnd MSG_TYPE = 5 //PlayEnd
|
||||
MSG_TYPE__PlayEndResult MSG_TYPE = 6 //PlayEndResult
|
||||
MSG_TYPE__Report MSG_TYPE = 7 //Report
|
||||
MSG_TYPE__ReportResult MSG_TYPE = 8 //ReportResult
|
||||
MSG_TYPE__GetRank MSG_TYPE = 9 //GetRank
|
||||
MSG_TYPE__GetRankResult MSG_TYPE = 10 //GetRankResult
|
||||
MSG_TYPE__NotifyNewAudience MSG_TYPE = 11 //NotifyNewAudience
|
||||
MSG_TYPE__NotifyAudienceAction MSG_TYPE = 12 //NotifyAudienceAction
|
||||
)
|
||||
|
||||
// Enum value maps for MSG_TYPE.
|
||||
var (
|
||||
MSG_TYPE_name = map[int32]string{
|
||||
0: "_ERROR",
|
||||
1: "_Login",
|
||||
2: "_LoginResult",
|
||||
3: "_PlayStart",
|
||||
4: "_PlayStartResult",
|
||||
5: "_PlayEnd",
|
||||
6: "_PlayEndResult",
|
||||
7: "_Report",
|
||||
8: "_ReportResult",
|
||||
9: "_GetRank",
|
||||
10: "_GetRankResult",
|
||||
11: "_NotifyNewAudience",
|
||||
12: "_NotifyAudienceAction",
|
||||
}
|
||||
MSG_TYPE_value = map[string]int32{
|
||||
"_ERROR": 0,
|
||||
"_Login": 1,
|
||||
"_LoginResult": 2,
|
||||
"_PlayStart": 3,
|
||||
"_PlayStartResult": 4,
|
||||
"_PlayEnd": 5,
|
||||
"_PlayEndResult": 6,
|
||||
"_Report": 7,
|
||||
"_ReportResult": 8,
|
||||
"_GetRank": 9,
|
||||
"_GetRankResult": 10,
|
||||
"_NotifyNewAudience": 11,
|
||||
"_NotifyAudienceAction": 12,
|
||||
}
|
||||
)
|
||||
|
||||
func (x MSG_TYPE) Enum() *MSG_TYPE {
|
||||
p := new(MSG_TYPE)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x MSG_TYPE) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (MSG_TYPE) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgtype_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (MSG_TYPE) Type() protoreflect.EnumType {
|
||||
return &file_msgtype_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x MSG_TYPE) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MSG_TYPE.Descriptor instead.
|
||||
func (MSG_TYPE) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type ERROR_CODE int32
|
||||
|
||||
const (
|
||||
ERROR_CODE_SUCCESS ERROR_CODE = 0
|
||||
ERROR_CODE_FAIL ERROR_CODE = 1
|
||||
ERROR_CODE_INVALID_APPID ERROR_CODE = 2
|
||||
ERROR_CODE_INVALID_TOKEN ERROR_CODE = 3
|
||||
ERROR_CODE_GAME_IS_RUNNING ERROR_CODE = 4
|
||||
ERROR_CODE_GAME_IS_STOPPED ERROR_CODE = 5
|
||||
)
|
||||
|
||||
// Enum value maps for ERROR_CODE.
|
||||
var (
|
||||
ERROR_CODE_name = map[int32]string{
|
||||
0: "SUCCESS",
|
||||
1: "FAIL",
|
||||
2: "INVALID_APPID",
|
||||
3: "INVALID_TOKEN",
|
||||
4: "GAME_IS_RUNNING",
|
||||
5: "GAME_IS_STOPPED",
|
||||
}
|
||||
ERROR_CODE_value = map[string]int32{
|
||||
"SUCCESS": 0,
|
||||
"FAIL": 1,
|
||||
"INVALID_APPID": 2,
|
||||
"INVALID_TOKEN": 3,
|
||||
"GAME_IS_RUNNING": 4,
|
||||
"GAME_IS_STOPPED": 5,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ERROR_CODE) Enum() *ERROR_CODE {
|
||||
p := new(ERROR_CODE)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ERROR_CODE) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ERROR_CODE) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_msgtype_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (ERROR_CODE) Type() protoreflect.EnumType {
|
||||
return &file_msgtype_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x ERROR_CODE) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ERROR_CODE.Descriptor instead.
|
||||
func (ERROR_CODE) EnumDescriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *Error) Reset() {
|
||||
*x = Error{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_msgtype_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Error) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (x *Error) FromDB(data []byte) error {
|
||||
return proto.Unmarshal(data, x)
|
||||
}
|
||||
|
||||
func (x *Error) ToDB() ([]byte, error) {
|
||||
return proto.Marshal(x)
|
||||
}
|
||||
|
||||
func (*Error) ProtoMessage() {}
|
||||
|
||||
func (x *Error) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_msgtype_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Error.ProtoReflect.Descriptor instead.
|
||||
func (*Error) Descriptor() ([]byte, []int) {
|
||||
return file_msgtype_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
var File_msgtype_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_msgtype_proto_rawDesc = []byte{
|
||||
0x0a, 0x0d, 0x6d, 0x73, 0x67, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x2a, 0xf1, 0x01, 0x0a, 0x08, 0x4d, 0x53, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x5f, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x5f, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x5f, 0x50, 0x6c, 0x61,
|
||||
0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x5f, 0x50, 0x6c, 0x61,
|
||||
0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x10, 0x04, 0x12, 0x0c,
|
||||
0x0a, 0x08, 0x5f, 0x50, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e,
|
||||
0x5f, 0x50, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x10, 0x06,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x5f, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x10, 0x07, 0x12, 0x11, 0x0a,
|
||||
0x0d, 0x5f, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x10, 0x08,
|
||||
0x12, 0x0c, 0x0a, 0x08, 0x5f, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x6b, 0x10, 0x09, 0x12, 0x12,
|
||||
0x0a, 0x0e, 0x5f, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
||||
0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4e, 0x65, 0x77,
|
||||
0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x5f, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x10, 0x0c, 0x2a, 0x73, 0x0a, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43,
|
||||
0x4f, 0x44, 0x45, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00,
|
||||
0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e,
|
||||
0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x41, 0x50, 0x50, 0x49, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a,
|
||||
0x0d, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x03,
|
||||
0x12, 0x13, 0x0a, 0x0f, 0x47, 0x41, 0x4d, 0x45, 0x5f, 0x49, 0x53, 0x5f, 0x52, 0x55, 0x4e, 0x4e,
|
||||
0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x47, 0x41, 0x4d, 0x45, 0x5f, 0x49, 0x53,
|
||||
0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x05, 0x42, 0x05, 0x5a, 0x03, 0x70, 0x62,
|
||||
0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_msgtype_proto_rawDescOnce sync.Once
|
||||
file_msgtype_proto_rawDescData = file_msgtype_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_msgtype_proto_rawDescGZIP() []byte {
|
||||
file_msgtype_proto_rawDescOnce.Do(func() {
|
||||
file_msgtype_proto_rawDescData = protoimpl.X.CompressGZIP(file_msgtype_proto_rawDescData)
|
||||
})
|
||||
return file_msgtype_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_msgtype_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_msgtype_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_msgtype_proto_goTypes = []interface{}{
|
||||
(MSG_TYPE)(0), // 0: message.MSG_TYPE
|
||||
(ERROR_CODE)(0), // 1: message.ERROR_CODE
|
||||
(*Error)(nil), // 2: message.Error
|
||||
}
|
||||
var file_msgtype_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_msgtype_proto_init() }
|
||||
func file_msgtype_proto_init() {
|
||||
if File_msgtype_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_msgtype_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Error); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_msgtype_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_msgtype_proto_goTypes,
|
||||
DependencyIndexes: file_msgtype_proto_depIdxs,
|
||||
EnumInfos: file_msgtype_proto_enumTypes,
|
||||
MessageInfos: file_msgtype_proto_msgTypes,
|
||||
}.Build()
|
||||
File_msgtype_proto = out.File
|
||||
file_msgtype_proto_rawDesc = nil
|
||||
file_msgtype_proto_goTypes = nil
|
||||
file_msgtype_proto_depIdxs = nil
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type RankInfo struct {
|
||||
OpenId string
|
||||
Score int32
|
||||
}
|
||||
|
||||
var client *redis.Client
|
||||
|
||||
func init() {
|
||||
url := "redis://:adhd@123@101.35.201.220:6379/1?protocol=3"
|
||||
opts, err := redis.ParseURL(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
client = redis.NewClient(opts)
|
||||
}
|
||||
|
||||
func AddScore(appId string, scoreMap map[string]int32) error {
|
||||
ctx := context.Background()
|
||||
pip := client.Pipeline()
|
||||
for openId, score := range scoreMap {
|
||||
key := fmt.Sprintf("Score_%s", appId)
|
||||
pip.ZIncrBy(ctx, key, float64(score), openId)
|
||||
}
|
||||
_, err := pip.Exec(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRank(appId string, topCount int32) ([]*RankInfo, error) {
|
||||
ctx := context.Background()
|
||||
key := fmt.Sprintf("Score_%s_*", appId)
|
||||
cmd := client.ZRevRangeWithScores(ctx, key, 0, int64(topCount))
|
||||
result, err := cmd.Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rankList := make([]*RankInfo, 0)
|
||||
for _, info := range result {
|
||||
rankList = append(rankList, &RankInfo{
|
||||
OpenId: info.Member.(string),
|
||||
Score: int32(info.Score),
|
||||
})
|
||||
}
|
||||
return rankList, nil
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"app/service/main/in_obj"
|
||||
"app/service/main/message/pb"
|
||||
"app/service/main/redis"
|
||||
"core/network"
|
||||
)
|
||||
|
||||
func NewUser(mgr in_obj.IGameMgr) *User {
|
||||
return &User{mgr: mgr}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
network.BaseNetHandler
|
||||
mgr in_obj.IGameMgr
|
||||
appId string
|
||||
roomId string
|
||||
isRunning bool
|
||||
audienceSet map[int32]bool
|
||||
msgChan chan func()
|
||||
closeChan chan struct{}
|
||||
}
|
||||
|
||||
func (s *User) OnSessionCreated() {
|
||||
//主协程
|
||||
s.msgChan = make(chan func())
|
||||
s.closeChan = make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case f := <-s.msgChan:
|
||||
f()
|
||||
case <-s.closeChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *User) OnSessionClosed() {
|
||||
if !s.isRunning {
|
||||
return
|
||||
}
|
||||
s.setPushActive(false)
|
||||
s.isRunning = false
|
||||
s.closeChan <- struct{}{}
|
||||
}
|
||||
|
||||
func (s *User) OnRecv(msgId int32, data interface{}) {
|
||||
s.msgChan <- func() {
|
||||
switch msgId {
|
||||
case int32(pb.MSG_TYPE__Login):
|
||||
s.OnLogin(data.(*pb.Login))
|
||||
case int32(pb.MSG_TYPE__PlayStart):
|
||||
s.OnPlayStart(data.(*pb.PlayStart))
|
||||
case int32(pb.MSG_TYPE__PlayEnd):
|
||||
s.OnPlayEnd(data.(*pb.PlayEnd))
|
||||
case int32(pb.MSG_TYPE__Report):
|
||||
s.OnReport(data.(*pb.Report))
|
||||
case int32(pb.MSG_TYPE__GetRank):
|
||||
s.OnGetRank(data.(*pb.GetRank))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *User) OnLogin(msg *pb.Login) {
|
||||
roomId, uid, nickName, result := s.mgr.Login(msg.AppId, msg.Token)
|
||||
s.appId = msg.AppId
|
||||
s.roomId = roomId
|
||||
s.SendMsg(&pb.LoginResult{
|
||||
Result: result,
|
||||
RoomId: roomId,
|
||||
UID: uid,
|
||||
NickName: nickName,
|
||||
})
|
||||
}
|
||||
func (s *User) OnPlayStart(msg *pb.PlayStart) {
|
||||
if s.isRunning {
|
||||
s.SendMsg(&pb.PlayStartResult{Result: pb.ERROR_CODE_GAME_IS_RUNNING})
|
||||
return
|
||||
}
|
||||
s.setPushActive(true)
|
||||
s.SendMsg(&pb.PlayStartResult{Result: pb.ERROR_CODE_SUCCESS})
|
||||
}
|
||||
func (s *User) OnPlayEnd(msg *pb.PlayEnd) {
|
||||
if !s.isRunning {
|
||||
s.SendMsg(&pb.PlayEndResult{Result: pb.ERROR_CODE_GAME_IS_STOPPED})
|
||||
return
|
||||
}
|
||||
s.setPushActive(false)
|
||||
s.SendMsg(&pb.PlayEndResult{Result: pb.ERROR_CODE_SUCCESS})
|
||||
}
|
||||
func (s *User) OnReport(msg *pb.Report) {
|
||||
scoreMap := map[string]int32{}
|
||||
for _, info := range msg.Info {
|
||||
scoreMap[info.OpenId] = info.Score
|
||||
}
|
||||
err := redis.AddScore(s.appId, scoreMap)
|
||||
if err != nil {
|
||||
s.SendMsg(&pb.ReportResult{Result: pb.ERROR_CODE_FAIL})
|
||||
return
|
||||
}
|
||||
s.SendMsg(&pb.ReportResult{Result: pb.ERROR_CODE_SUCCESS})
|
||||
}
|
||||
func (s *User) OnGetRank(msg *pb.GetRank) {
|
||||
rankList, err := redis.GetRank(s.appId, msg.TopCount)
|
||||
if err != nil {
|
||||
s.SendMsg(&pb.GetRankResult{Result: pb.ERROR_CODE_FAIL})
|
||||
return
|
||||
}
|
||||
var ret []*pb.ReportInfo
|
||||
for _, info := range rankList {
|
||||
ret = append(ret, &pb.ReportInfo{
|
||||
OpenId: info.OpenId,
|
||||
Score: info.Score,
|
||||
})
|
||||
}
|
||||
s.SendMsg(&pb.GetRankResult{Result: pb.ERROR_CODE_SUCCESS, Info: ret})
|
||||
}
|
||||
|
||||
func (s *User) setPushActive(isActive bool) {
|
||||
s.isRunning = isActive
|
||||
if isActive {
|
||||
s.mgr.StartTask(s.appId, s.roomId, "1")
|
||||
s.mgr.StartTask(s.appId, s.roomId, "2")
|
||||
s.mgr.StartTask(s.appId, s.roomId, "3")
|
||||
} else {
|
||||
s.mgr.StopTask(s.appId, s.roomId, "1")
|
||||
s.mgr.StopTask(s.appId, s.roomId, "2")
|
||||
s.mgr.StopTask(s.appId, s.roomId, "3")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"core/network"
|
||||
)
|
||||
|
||||
func NewUser() *User {
|
||||
return &User{}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
network.BaseNetHandler
|
||||
}
|
||||
|
||||
func (s *User) OnSessionCreated() {
|
||||
}
|
||||
|
||||
func (s *User) OnSessionClosed() {
|
||||
}
|
||||
|
||||
func (s *User) OnRecv(msgId int32, data interface{}) {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue