多租户更改

This commit is contained in:
richjohnrambo
2026-08-11 15:59:57 +08:00
parent 6c800de67d
commit c2076721fc
453 changed files with 102349 additions and 47 deletions
+23
View File
@@ -0,0 +1,23 @@
# Protocol Buffer and gRPC definitions
Definitions for Tinode [gRPC](https://grpc.io/) client and plugins.
Tinode gRPC clients must implement rpc service `Node`, Tinode plugins `Plugin`.
Generated `Go` and `Python` code is included. For a sample `Python` implementation of a command line client see [tn-cli](../tn-cli/).
For a partial plugin implementation see [chatbot](../chatbot/).
If you want to make changes, you have to install protobuffers tool chain and gRPC:
```
$ python -m pip install grpcio grpcio-tools googleapis-common-protos
```
To generate `Go` bindings add the following comment to your code and run `go generate` (your actual path to `/pbx` may be different):
```
//go:generate protoc --proto_path=../pbx --go_out=plugins=grpc:../pbx ../pbx/model.proto
```
To generate `Python` bindings:
```
python -m grpc_tools.protoc -I../pbx --python_out=. --grpc_python_out=. ../pbx/model.proto
```
Regular → Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
protoc --go_out=../pbx --go_opt=paths=source_relative --go-grpc_out=../pbx --go-grpc_opt=paths=source_relative model.proto
+5846
View File
File diff suppressed because it is too large Load Diff
+660
View File
@@ -0,0 +1,660 @@
syntax = "proto3";
package pbx;
option go_package = "github.com/tinode/chat/pbx";
// This is the methods that needs to be implemented by a gRPC client.
service Node {
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
rpc MessageLoop(stream ClientMsg) returns (stream ServerMsg) {}
// Large file upload: a request with a stream of chunks.
rpc LargeFileReceive(stream FileUpReq) returns (FileUpResp) {}
// Large file file download: a response with a stream of chunks.
rpc LargeFileServe(FileDownReq) returns (stream FileDownResp) {}
}
// Plugin interface.
service Plugin {
// This plugin method is called by Tinode server for every message received from the clients. The
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
// See possible values for ServerResp.status in RespCode below.
rpc FireHose(ClientReq) returns (ServerResp) {}
// An alteranative user and topic discovery mechanism.
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
rpc Find(SearchQuery) returns (SearchFound) {}
// The following methods are for the Tinode server to report individual events.
// Account created, updated or deleted
rpc Account(AccountEvent) returns (Unused) {}
// Topic created, updated [or deleted -- not supported yet]
rpc Topic(TopicEvent) returns (Unused) {}
// Subscription created, updated or deleted
rpc Subscription(SubscriptionEvent) returns (Unused) {}
// Message published or deleted
rpc Message(MessageEvent) returns (Unused) {}
}
// Dummy placeholder message.
message Unused {
}
// Common client/server messages
// Authentication level
enum AuthLevel {
NONE = 0;
ANON = 10;
AUTH = 20;
ROOT = 30;
}
// Client messages
// Topic default access mode
message DefaultAcsMode {
string auth = 1;
string anon = 2;
}
// Actual access mode
message AccessMode {
// Access mode requested by the user
string want = 1;
// Access mode granted to the user by the admin
string given = 2;
}
// SetSub: payload in set.sub request to update current subscription or invite another user, {sub.what} == "sub"
message SetSub {
// User affected by this request. Default (empty): current user
string user_id = 1;
// Access mode change, either Given or Want depending on context
string mode = 2;
}
// Credentials such as email or phone number
message ClientCred {
// Credential type, i.e. `email` or `tel`.
string method = 1;
// Value to verify, i.e. `user@example.com` or `+18003287448`
string value = 2;
// Verification response
string response = 3;
// Request parameters, such as preferences or country code.
map<string, bytes> params = 4;
}
// SetDesc: C2S in set.what == "desc" and sub.init message
message SetDesc {
DefaultAcsMode default_acs = 1;
bytes public = 2;
bytes private = 3;
bytes trusted = 4;
}
message SeqRange {
int32 low = 1;
int32 hi = 2;
}
message GetOpts {
// Timestamp in milliseconds since epoch 01/01/1970
int64 if_modified_since = 1;
// Limit search to this user ID
string user = 2;
// Limit search results to one topic;
string topic = 3;
// Load messages with seq id equal or greater than this
int32 since_id = 4;
// Load messages with seq id lower than this
int32 before_id = 5;
// Maximum number of results to return
int32 limit = 6;
// Load messages by id or ranges of ids
repeated SeqRange ranges = 7;
}
message GetQuery {
string what = 1;
// Parameters of "desc" request
GetOpts desc = 2;
// Parameters of "sub" request
GetOpts sub = 3;
// Parameters of "data" request
GetOpts data = 4;
}
message SetQuery {
// Topic metadata, new topic & new subscriptions only
SetDesc desc = 1;
// Subscription parameters
SetSub sub = 2;
// Indexable tags
repeated string tags = 3;
// Credential being updated.
ClientCred cred = 4;
// Auxiliary data.
map<string, bytes> aux = 5;
}
// Client handshake
message ClientHi {
string id = 1;
string user_agent = 2;
string ver = 3;
string device_id = 4;
string lang = 5;
string platform = 6;
bool background = 7;
string tenant = 8;
}
// User creation message {acc}
message ClientAcc {
string id = 1;
// User being created or updated
string user_id = 2;
// The initial authentication scheme the account can use
string scheme = 3;
// Shared secret
bytes secret = 4;
// Authenticate session with the newly created account
bool login = 5;
// Indexable tags for user discovery
repeated string tags = 6;
// User initialization data when creating a new user, otherwise ignored
SetDesc desc = 7;
// Credentials for verification.
repeated ClientCred cred = 8;
// Authentication token used for resetting a password.
bytes token = 9;
// Account state: normal ("ok"), suspended
string state = 10;
// AuthLevel
AuthLevel auth_level = 11;
// Temporary auth params for one-off actions like password reset.
string tmp_scheme = 12;
bytes tmp_secret = 13;
}
// Login {login} message
message ClientLogin {
string id = 1;
// Authentication scheme
string scheme = 2;
// Shared secret
bytes secret = 3;
// Credentials for verification.
repeated ClientCred cred = 4;
}
// Subscription request {sub} message
message ClientSub {
string id = 1;
string topic = 2;
// mirrors {set}
SetQuery set_query = 3;
// mirrors {get}
GetQuery get_query = 4;
}
// Unsubscribe {leave} request message
message ClientLeave {
string id = 1;
string topic = 2;
bool unsub = 3;
}
// ClientPub is client's request to publish data to topic subscribers {pub}
message ClientPub {
string id = 1;
string topic = 2;
bool no_echo = 3;
map<string, bytes> head = 4;
bytes content = 5;
}
// Query topic state {get}
message ClientGet {
string id = 1;
string topic = 2;
GetQuery query = 3;
}
// Update topic state {set}
message ClientSet {
string id = 1;
string topic = 2;
SetQuery query = 3;
}
// ClientDel delete messages or topic
message ClientDel {
string id = 1;
string topic = 2;
// What to delete, either "msg" to delete messages (default) or "topic" to delete the topic or "sub"
// to delete a subscription to topic.
enum What {
// Invalid value. The name must be globally unique.
X0 = 0;
MSG = 1;
TOPIC = 2;
SUB = 3;
USER = 4;
CRED = 5;
}
What what = 3;
// Delete messages by id or range of ids
repeated SeqRange del_seq = 4;
// User ID of the subscription to delete
string user_id = 5;
// Credential to delete.
ClientCred cred = 6;
// Request to hard-delete messages for all users, if such option is available.
bool hard = 7;
}
enum InfoNote {
// Invalid value. The name must be globally unique.
X1 = 0;
READ = 1;
RECV = 2;
KP = 3;
CALL = 4;
}
enum CallEvent {
// Invalid value. The name must be globally unique.
X2 = 0;
ACCEPT = 1;
ANSWER = 2;
HANG_UP = 3;
ICE_CANDIDATE = 4;
INVITE = 5;
OFFER = 6;
RINGING = 7;
}
// ClientNote is a client-generated notification for topic subscribers
message ClientNote {
string topic = 1;
// what is being reported: "recv" - message received, "read" - message read,
// "kp" - typing notification, "call" - voice/video call
InfoNote what = 2;
// Server-issued message ID being reported
int32 seq_id = 3;
// Client's count of unread messages to report back to the server. Used in push notifications on iOS.
int32 unread = 4;
// Call event.
CallEvent event = 5;
// Arbitrary json payload (used in video calls).
bytes payload = 6;
}
message ClientExtra {
repeated string attachments = 1;
// Root user may send messages on behalf of other users.
string on_behalf_of = 2;
AuthLevel auth_level = 3;
}
message ClientMsg {
oneof Message {
ClientHi hi = 1;
ClientAcc acc = 2;
ClientLogin login = 3;
ClientSub sub = 4;
ClientLeave leave = 5;
ClientPub pub = 6;
ClientGet get = 7;
ClientSet set = 8;
ClientDel del = 9;
ClientNote note = 10;
}
// Additional message parameters.
ClientExtra extra = 13;
}
// ************************
// Server response messages
// Credentials
message ServerCred {
// Credential type, i.e. `email` or `tel`.
string method = 1;
// Value to verify, i.e. `user@example.com` or `+18003287448`
string value = 2;
// Indicator that the credential is validated
bool done = 3;
}
// Topic description, S2C in Meta message
message TopicDesc {
int64 created_at = 1;
int64 updated_at = 2;
int64 touched_at = 3;
DefaultAcsMode defacs = 4;
AccessMode acs = 5;
int32 seq_id = 6;
int32 read_id = 7;
int32 recv_id = 8;
int32 del_id = 9;
bytes public = 10;
bytes private = 11;
string state = 12;
int64 state_at = 13;
bytes trusted = 14;
bool is_chan = 17; // 17!
bool online = 18;
// P2P only: other user's last online timestamp & user agent
int64 last_seen_time = 15;
string last_seen_user_agent = 16;
}
// MsgTopicSub: topic subscription details, sent in Meta message
message TopicSub {
int64 updated_at = 1;
int64 deleted_at = 2;
bool online = 3;
AccessMode acs = 4;
int32 read_id = 5;
int32 recv_id = 6;
bytes public = 7;
bytes trusted = 16; // 16!
bytes private = 8;
// Response to non-'me' topic
// Uid of the subscribed user
string user_id = 9;
// 'me' topic only
// Topic name of this subscription
string topic = 10;
int64 touched_at = 11;
// ID of the last {data} message in a topic
int32 seq_id = 12;
// Messages are deleted up to this ID
int32 del_id = 13;
// P2P topics only:
// Other user's last online timestamp & user agent
int64 last_seen_time = 14;
string last_seen_user_agent = 15;
}
message DelValues {
int32 del_id = 1;
repeated SeqRange del_seq = 2;
}
// {ctrl} message
message ServerCtrl {
string id = 1;
string topic = 2;
int32 code = 3;
string text = 4;
map<string, bytes> params = 5;
}
// {data} message
message ServerData {
string topic = 1;
// ID of the user who originated the message as {pub}, could be empty if sent by the system
string from_user_id = 2;
// Timestamp when the message was sent.
int64 timestamp = 7;
// Timestamp when the message was deleted or 0. Milliseconds since the epoch 01/01/1970
int64 deleted_at = 3;
int32 seq_id = 4;
map<string, bytes> head = 5;
bytes content = 6;
}
// {pres} message
message ServerPres {
string topic = 1;
string src = 2;
enum What {
// Invalid value. The name must be globally unique.
X3 = 0;
ON = 1;
OFF = 2;
UA = 3;
UPD = 4;
GONE = 5;
ACS = 6;
TERM = 7;
MSG = 8;
READ = 9;
RECV = 10;
DEL = 11;
TAGS = 12;
AUX = 13;
}
What what = 3;
string user_agent = 4;
int32 seq_id = 5;
int32 del_id = 6;
repeated SeqRange del_seq = 7;
string target_user_id = 8;
string actor_user_id = 9;
AccessMode acs = 10;
}
// {meta} message
message ServerMeta {
string id = 1;
string topic = 2;
TopicDesc desc = 3;
repeated TopicSub sub = 4;
DelValues del = 5;
repeated string tags = 6;
repeated ServerCred cred = 7;
map<string, bytes> aux = 8;
}
// {info} message: server-side copy of ClientNote with From and optional Src added.
message ServerInfo {
string topic = 1;
string from_user_id = 2;
InfoNote what = 3;
int32 seq_id = 4;
string src = 5;
CallEvent event = 6;
bytes payload = 7;
}
// Cumulative message
message ServerMsg {
oneof Message {
ServerCtrl ctrl = 1;
ServerData data = 2;
ServerPres pres = 3;
ServerMeta meta = 4;
ServerInfo info = 5;
}
// DEPRECATED. Will be removed soon.
// When response is sent to Root, send internal topic name too.
string topic = 6 [deprecated = true];
}
// Plugin response codes
enum RespCode {
// Instruct Tinode server to continue with default processing of the client request.
CONTINUE = 0;
// Drop the request as if the client did not send it
DROP = 1;
// Send the the provided srvmsg response to the client. ServerResp must contain non-zero
// srvmsg.
RESPOND = 2;
// Replace client's original request with the provided clmsg request then continue with
// processing. ServerResp must contain non-zero clmsg.
REPLACE = 3;
}
message ServerResp {
RespCode status = 1;
ServerMsg srvmsg = 2;
ClientMsg clmsg = 3;
}
// Context message
message Session {
string session_id = 1;
string user_id = 2;
AuthLevel auth_level = 3;
string remote_addr = 4;
string user_agent = 5;
string device_id = 6;
string language = 7;
}
message ClientReq {
ClientMsg msg = 1;
Session sess = 2;
}
// Search
message SearchQuery {
string user_id = 1;
string query = 2;
}
message SearchFound {
RespCode status = 1;
// New search query If status == REPLACE, otherwise unset.
string query = 2;
// Search results.
repeated TopicSub result = 3;
}
// CRUD event messages
enum Crud {
CREATE = 0;
UPDATE = 1;
DELETE = 2;
}
message TopicEvent {
Crud action = 1;
string name = 2;
TopicDesc desc = 3;
}
message AccountEvent {
Crud action = 1;
string user_id = 2;
DefaultAcsMode default_acs = 3;
bytes public = 4;
// Indexable tags for user discovery
repeated string tags = 8;
}
message SubscriptionEvent {
Crud action = 1;
string topic = 2;
string user_id = 3;
int32 del_id = 4;
int32 read_id = 5;
int32 recv_id = 6;
AccessMode mode = 7;
bytes private = 8;
}
message MessageEvent {
Crud action = 1;
ServerData msg = 2;
}
// Large file handling.
message Auth {
string scheme = 1;
string secret = 2;
}
// File description.
message FileMeta {
string name = 1;
string mime_type = 2;
string etag = 3;
int64 size = 4;
}
// File upload request.
message FileUpReq {
// Request ID.
string id = 1;
// Request authentication credentials.
Auth auth = 2;
// The topic this upload belongs to.
string topic = 3;
// Uploaded metadata.
FileMeta meta = 4;
// File bytes being uploaded.
bytes content = 5;
}
// Response to file upload.
message FileUpResp {
// Response ID.
string id = 1;
// Response code.
int32 code = 2;
// Response text.
string text = 3;
FileMeta meta = 4;
// New upload location.
string redir_url = 5;
}
// File download request.
message FileDownReq {
// Request ID
string id = 1;
// Request authentication credentials.
Auth auth = 2;
// File URI to download.
string uri = 3;
// ETag
string if_modified = 4;
}
// Response to file download.
message FileDownResp {
// Response ID.
string id = 1;
// Response code.
int32 code = 2;
// Response text.
string text = 3;
FileMeta meta = 4;
// File location.
string redir_url = 5;
// File bytes.
bytes content = 6;
}
+560
View File
@@ -0,0 +1,560 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.12
// source: model.proto
package pbx
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// NodeClient is the client API for Node service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type NodeClient interface {
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
MessageLoop(ctx context.Context, opts ...grpc.CallOption) (Node_MessageLoopClient, error)
// Large file upload: a request with a stream of chunks.
LargeFileReceive(ctx context.Context, opts ...grpc.CallOption) (Node_LargeFileReceiveClient, error)
// Large file file download: a response with a stream of chunks.
LargeFileServe(ctx context.Context, in *FileDownReq, opts ...grpc.CallOption) (Node_LargeFileServeClient, error)
}
type nodeClient struct {
cc grpc.ClientConnInterface
}
func NewNodeClient(cc grpc.ClientConnInterface) NodeClient {
return &nodeClient{cc}
}
func (c *nodeClient) MessageLoop(ctx context.Context, opts ...grpc.CallOption) (Node_MessageLoopClient, error) {
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[0], "/pbx.Node/MessageLoop", opts...)
if err != nil {
return nil, err
}
x := &nodeMessageLoopClient{stream}
return x, nil
}
type Node_MessageLoopClient interface {
Send(*ClientMsg) error
Recv() (*ServerMsg, error)
grpc.ClientStream
}
type nodeMessageLoopClient struct {
grpc.ClientStream
}
func (x *nodeMessageLoopClient) Send(m *ClientMsg) error {
return x.ClientStream.SendMsg(m)
}
func (x *nodeMessageLoopClient) Recv() (*ServerMsg, error) {
m := new(ServerMsg)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *nodeClient) LargeFileReceive(ctx context.Context, opts ...grpc.CallOption) (Node_LargeFileReceiveClient, error) {
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[1], "/pbx.Node/LargeFileReceive", opts...)
if err != nil {
return nil, err
}
x := &nodeLargeFileReceiveClient{stream}
return x, nil
}
type Node_LargeFileReceiveClient interface {
Send(*FileUpReq) error
CloseAndRecv() (*FileUpResp, error)
grpc.ClientStream
}
type nodeLargeFileReceiveClient struct {
grpc.ClientStream
}
func (x *nodeLargeFileReceiveClient) Send(m *FileUpReq) error {
return x.ClientStream.SendMsg(m)
}
func (x *nodeLargeFileReceiveClient) CloseAndRecv() (*FileUpResp, error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
m := new(FileUpResp)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *nodeClient) LargeFileServe(ctx context.Context, in *FileDownReq, opts ...grpc.CallOption) (Node_LargeFileServeClient, error) {
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[2], "/pbx.Node/LargeFileServe", opts...)
if err != nil {
return nil, err
}
x := &nodeLargeFileServeClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Node_LargeFileServeClient interface {
Recv() (*FileDownResp, error)
grpc.ClientStream
}
type nodeLargeFileServeClient struct {
grpc.ClientStream
}
func (x *nodeLargeFileServeClient) Recv() (*FileDownResp, error) {
m := new(FileDownResp)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// NodeServer is the server API for Node service.
// All implementations must embed UnimplementedNodeServer
// for forward compatibility
type NodeServer interface {
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
MessageLoop(Node_MessageLoopServer) error
// Large file upload: a request with a stream of chunks.
LargeFileReceive(Node_LargeFileReceiveServer) error
// Large file file download: a response with a stream of chunks.
LargeFileServe(*FileDownReq, Node_LargeFileServeServer) error
mustEmbedUnimplementedNodeServer()
}
// UnimplementedNodeServer must be embedded to have forward compatible implementations.
type UnimplementedNodeServer struct {
}
func (UnimplementedNodeServer) MessageLoop(Node_MessageLoopServer) error {
return status.Errorf(codes.Unimplemented, "method MessageLoop not implemented")
}
func (UnimplementedNodeServer) LargeFileReceive(Node_LargeFileReceiveServer) error {
return status.Errorf(codes.Unimplemented, "method LargeFileReceive not implemented")
}
func (UnimplementedNodeServer) LargeFileServe(*FileDownReq, Node_LargeFileServeServer) error {
return status.Errorf(codes.Unimplemented, "method LargeFileServe not implemented")
}
func (UnimplementedNodeServer) mustEmbedUnimplementedNodeServer() {}
// UnsafeNodeServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to NodeServer will
// result in compilation errors.
type UnsafeNodeServer interface {
mustEmbedUnimplementedNodeServer()
}
func RegisterNodeServer(s grpc.ServiceRegistrar, srv NodeServer) {
s.RegisterService(&Node_ServiceDesc, srv)
}
func _Node_MessageLoop_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(NodeServer).MessageLoop(&nodeMessageLoopServer{stream})
}
type Node_MessageLoopServer interface {
Send(*ServerMsg) error
Recv() (*ClientMsg, error)
grpc.ServerStream
}
type nodeMessageLoopServer struct {
grpc.ServerStream
}
func (x *nodeMessageLoopServer) Send(m *ServerMsg) error {
return x.ServerStream.SendMsg(m)
}
func (x *nodeMessageLoopServer) Recv() (*ClientMsg, error) {
m := new(ClientMsg)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _Node_LargeFileReceive_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(NodeServer).LargeFileReceive(&nodeLargeFileReceiveServer{stream})
}
type Node_LargeFileReceiveServer interface {
SendAndClose(*FileUpResp) error
Recv() (*FileUpReq, error)
grpc.ServerStream
}
type nodeLargeFileReceiveServer struct {
grpc.ServerStream
}
func (x *nodeLargeFileReceiveServer) SendAndClose(m *FileUpResp) error {
return x.ServerStream.SendMsg(m)
}
func (x *nodeLargeFileReceiveServer) Recv() (*FileUpReq, error) {
m := new(FileUpReq)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _Node_LargeFileServe_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(FileDownReq)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(NodeServer).LargeFileServe(m, &nodeLargeFileServeServer{stream})
}
type Node_LargeFileServeServer interface {
Send(*FileDownResp) error
grpc.ServerStream
}
type nodeLargeFileServeServer struct {
grpc.ServerStream
}
func (x *nodeLargeFileServeServer) Send(m *FileDownResp) error {
return x.ServerStream.SendMsg(m)
}
// Node_ServiceDesc is the grpc.ServiceDesc for Node service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Node_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pbx.Node",
HandlerType: (*NodeServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "MessageLoop",
Handler: _Node_MessageLoop_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "LargeFileReceive",
Handler: _Node_LargeFileReceive_Handler,
ClientStreams: true,
},
{
StreamName: "LargeFileServe",
Handler: _Node_LargeFileServe_Handler,
ServerStreams: true,
},
},
Metadata: "model.proto",
}
// PluginClient is the client API for Plugin service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PluginClient interface {
// This plugin method is called by Tinode server for every message received from the clients. The
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
// See possible values for ServerResp.status in RespCode below.
FireHose(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*ServerResp, error)
// An alteranative user and topic discovery mechanism.
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
Find(ctx context.Context, in *SearchQuery, opts ...grpc.CallOption) (*SearchFound, error)
// Account created, updated or deleted
Account(ctx context.Context, in *AccountEvent, opts ...grpc.CallOption) (*Unused, error)
// Topic created, updated [or deleted -- not supported yet]
Topic(ctx context.Context, in *TopicEvent, opts ...grpc.CallOption) (*Unused, error)
// Subscription created, updated or deleted
Subscription(ctx context.Context, in *SubscriptionEvent, opts ...grpc.CallOption) (*Unused, error)
// Message published or deleted
Message(ctx context.Context, in *MessageEvent, opts ...grpc.CallOption) (*Unused, error)
}
type pluginClient struct {
cc grpc.ClientConnInterface
}
func NewPluginClient(cc grpc.ClientConnInterface) PluginClient {
return &pluginClient{cc}
}
func (c *pluginClient) FireHose(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*ServerResp, error) {
out := new(ServerResp)
err := c.cc.Invoke(ctx, "/pbx.Plugin/FireHose", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *pluginClient) Find(ctx context.Context, in *SearchQuery, opts ...grpc.CallOption) (*SearchFound, error) {
out := new(SearchFound)
err := c.cc.Invoke(ctx, "/pbx.Plugin/Find", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *pluginClient) Account(ctx context.Context, in *AccountEvent, opts ...grpc.CallOption) (*Unused, error) {
out := new(Unused)
err := c.cc.Invoke(ctx, "/pbx.Plugin/Account", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *pluginClient) Topic(ctx context.Context, in *TopicEvent, opts ...grpc.CallOption) (*Unused, error) {
out := new(Unused)
err := c.cc.Invoke(ctx, "/pbx.Plugin/Topic", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *pluginClient) Subscription(ctx context.Context, in *SubscriptionEvent, opts ...grpc.CallOption) (*Unused, error) {
out := new(Unused)
err := c.cc.Invoke(ctx, "/pbx.Plugin/Subscription", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *pluginClient) Message(ctx context.Context, in *MessageEvent, opts ...grpc.CallOption) (*Unused, error) {
out := new(Unused)
err := c.cc.Invoke(ctx, "/pbx.Plugin/Message", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PluginServer is the server API for Plugin service.
// All implementations must embed UnimplementedPluginServer
// for forward compatibility
type PluginServer interface {
// This plugin method is called by Tinode server for every message received from the clients. The
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
// See possible values for ServerResp.status in RespCode below.
FireHose(context.Context, *ClientReq) (*ServerResp, error)
// An alteranative user and topic discovery mechanism.
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
Find(context.Context, *SearchQuery) (*SearchFound, error)
// Account created, updated or deleted
Account(context.Context, *AccountEvent) (*Unused, error)
// Topic created, updated [or deleted -- not supported yet]
Topic(context.Context, *TopicEvent) (*Unused, error)
// Subscription created, updated or deleted
Subscription(context.Context, *SubscriptionEvent) (*Unused, error)
// Message published or deleted
Message(context.Context, *MessageEvent) (*Unused, error)
mustEmbedUnimplementedPluginServer()
}
// UnimplementedPluginServer must be embedded to have forward compatible implementations.
type UnimplementedPluginServer struct {
}
func (UnimplementedPluginServer) FireHose(context.Context, *ClientReq) (*ServerResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method FireHose not implemented")
}
func (UnimplementedPluginServer) Find(context.Context, *SearchQuery) (*SearchFound, error) {
return nil, status.Errorf(codes.Unimplemented, "method Find not implemented")
}
func (UnimplementedPluginServer) Account(context.Context, *AccountEvent) (*Unused, error) {
return nil, status.Errorf(codes.Unimplemented, "method Account not implemented")
}
func (UnimplementedPluginServer) Topic(context.Context, *TopicEvent) (*Unused, error) {
return nil, status.Errorf(codes.Unimplemented, "method Topic not implemented")
}
func (UnimplementedPluginServer) Subscription(context.Context, *SubscriptionEvent) (*Unused, error) {
return nil, status.Errorf(codes.Unimplemented, "method Subscription not implemented")
}
func (UnimplementedPluginServer) Message(context.Context, *MessageEvent) (*Unused, error) {
return nil, status.Errorf(codes.Unimplemented, "method Message not implemented")
}
func (UnimplementedPluginServer) mustEmbedUnimplementedPluginServer() {}
// UnsafePluginServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to PluginServer will
// result in compilation errors.
type UnsafePluginServer interface {
mustEmbedUnimplementedPluginServer()
}
func RegisterPluginServer(s grpc.ServiceRegistrar, srv PluginServer) {
s.RegisterService(&Plugin_ServiceDesc, srv)
}
func _Plugin_FireHose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).FireHose(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/FireHose",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).FireHose(ctx, req.(*ClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Plugin_Find_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchQuery)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).Find(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/Find",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).Find(ctx, req.(*SearchQuery))
}
return interceptor(ctx, in, info, handler)
}
func _Plugin_Account_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AccountEvent)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).Account(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/Account",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).Account(ctx, req.(*AccountEvent))
}
return interceptor(ctx, in, info, handler)
}
func _Plugin_Topic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TopicEvent)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).Topic(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/Topic",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).Topic(ctx, req.(*TopicEvent))
}
return interceptor(ctx, in, info, handler)
}
func _Plugin_Subscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SubscriptionEvent)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).Subscription(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/Subscription",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).Subscription(ctx, req.(*SubscriptionEvent))
}
return interceptor(ctx, in, info, handler)
}
func _Plugin_Message_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MessageEvent)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PluginServer).Message(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pbx.Plugin/Message",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PluginServer).Message(ctx, req.(*MessageEvent))
}
return interceptor(ctx, in, info, handler)
}
// Plugin_ServiceDesc is the grpc.ServiceDesc for Plugin service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Plugin_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pbx.Plugin",
HandlerType: (*PluginServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "FireHose",
Handler: _Plugin_FireHose_Handler,
},
{
MethodName: "Find",
Handler: _Plugin_Find_Handler,
},
{
MethodName: "Account",
Handler: _Plugin_Account_Handler,
},
{
MethodName: "Topic",
Handler: _Plugin_Topic_Handler,
},
{
MethodName: "Subscription",
Handler: _Plugin_Subscription_Handler,
},
{
MethodName: "Message",
Handler: _Plugin_Message_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "model.proto",
}
Regular → Executable
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
# Generate python gRPC bindings for Tinode. A command line parameter v=XX will use specified python version,
# i.e. ./generate-python.sh v=3 will use python3.
for line in $@; do
eval "$line"
done
python="python${v}"
# This generates python gRPC bindings for Tinode.
$python -m grpc_tools.protoc -I../pbx --python_out=../py_grpc/tinode_grpc --grpc_python_out=../py_grpc/tinode_grpc --pyi_out=../py_grpc/tinode_grpc ../pbx/model.proto
# Bindings are incompatible with Python packaging system. This is a fix.
$python py_fix.py
+11
View File
@@ -0,0 +1,11 @@
# grpc-tools generates python 2 file which does not work with
# python3 packaging system. This is a fix.
model_pb2_grpc = "../py_grpc/tinode_grpc/model_pb2_grpc.py"
with open(model_pb2_grpc, "r") as fh:
content = fh.read().replace("\nimport model_pb2 as model__pb2",
"\nfrom . import model_pb2 as model__pb2")
with open(model_pb2_grpc,"w") as fh:
fh.write(content)