snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
18
internal/proxyproto/convert.go
Normal file
18
internal/proxyproto/convert.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package proxyproto
|
||||
|
||||
import "github.com/centrifugal/centrifuge"
|
||||
|
||||
func DisconnectFromProto(s *Disconnect) *centrifuge.Disconnect {
|
||||
return ¢rifuge.Disconnect{
|
||||
Code: s.Code,
|
||||
Reason: s.Reason,
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorFromProto(s *Error) *centrifuge.Error {
|
||||
return ¢rifuge.Error{
|
||||
Code: s.Code,
|
||||
Message: s.Message,
|
||||
Temporary: s.Temporary,
|
||||
}
|
||||
}
|
||||
110
internal/proxyproto/decode.go
Normal file
110
internal/proxyproto/decode.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package proxyproto
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type ResponseDecoder interface {
|
||||
DecodeConnectResponse(data []byte) (*ConnectResponse, error)
|
||||
DecodeRefreshResponse(data []byte) (*RefreshResponse, error)
|
||||
DecodeRPCResponse(data []byte) (*RPCResponse, error)
|
||||
DecodeSubscribeResponse(data []byte) (*SubscribeResponse, error)
|
||||
DecodePublishResponse(data []byte) (*PublishResponse, error)
|
||||
DecodeSubRefreshResponse(data []byte) (*SubRefreshResponse, error)
|
||||
DecodeNotifyCacheEmptyResponse(data []byte) (*NotifyCacheEmptyResponse, error)
|
||||
DecodeMapPublishResponse(data []byte) (*MapPublishResponse, error)
|
||||
DecodeMapRemoveResponse(data []byte) (*MapRemoveResponse, error)
|
||||
DecodeSharedPollRefreshResponse(data []byte) (*SharedPollRefreshResponse, error)
|
||||
}
|
||||
|
||||
var _ ResponseDecoder = (*JSONDecoder)(nil)
|
||||
|
||||
type JSONDecoder struct{}
|
||||
|
||||
func (e *JSONDecoder) DecodeConnectResponse(data []byte) (*ConnectResponse, error) {
|
||||
var resp ConnectResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeRefreshResponse(data []byte) (*RefreshResponse, error) {
|
||||
var resp RefreshResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeRPCResponse(data []byte) (*RPCResponse, error) {
|
||||
var resp RPCResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeSubscribeResponse(data []byte) (*SubscribeResponse, error) {
|
||||
var resp SubscribeResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodePublishResponse(data []byte) (*PublishResponse, error) {
|
||||
var resp PublishResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeSubRefreshResponse(data []byte) (*SubRefreshResponse, error) {
|
||||
var resp SubRefreshResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeNotifyCacheEmptyResponse(data []byte) (*NotifyCacheEmptyResponse, error) {
|
||||
var resp NotifyCacheEmptyResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeMapPublishResponse(data []byte) (*MapPublishResponse, error) {
|
||||
var resp MapPublishResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeMapRemoveResponse(data []byte) (*MapRemoveResponse, error) {
|
||||
var resp MapRemoveResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (e *JSONDecoder) DecodeSharedPollRefreshResponse(data []byte) (*SharedPollRefreshResponse, error) {
|
||||
var resp SharedPollRefreshResponse
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
60
internal/proxyproto/encode.go
Normal file
60
internal/proxyproto/encode.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package proxyproto
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type RequestEncoder interface {
|
||||
EncodeConnectRequest(req *ConnectRequest) ([]byte, error)
|
||||
EncodeRefreshRequest(req *RefreshRequest) ([]byte, error)
|
||||
EncodeRPCRequest(req *RPCRequest) ([]byte, error)
|
||||
EncodeSubscribeRequest(req *SubscribeRequest) ([]byte, error)
|
||||
EncodePublishRequest(req *PublishRequest) ([]byte, error)
|
||||
EncodeSubRefreshRequest(req *SubRefreshRequest) ([]byte, error)
|
||||
EncodeNotifyCacheEmptyRequest(req *NotifyCacheEmptyRequest) ([]byte, error)
|
||||
EncodeMapPublishRequest(req *MapPublishRequest) ([]byte, error)
|
||||
EncodeMapRemoveRequest(req *MapRemoveRequest) ([]byte, error)
|
||||
EncodeSharedPollRefreshRequest(req *SharedPollRefreshRequest) ([]byte, error)
|
||||
}
|
||||
|
||||
var _ RequestEncoder = (*JSONEncoder)(nil)
|
||||
|
||||
type JSONEncoder struct{}
|
||||
|
||||
func (e *JSONEncoder) EncodeConnectRequest(req *ConnectRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeRefreshRequest(req *RefreshRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeRPCRequest(req *RPCRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeSubscribeRequest(req *SubscribeRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodePublishRequest(req *PublishRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeSubRefreshRequest(req *SubRefreshRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeNotifyCacheEmptyRequest(req *NotifyCacheEmptyRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeMapPublishRequest(req *MapPublishRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeMapRemoveRequest(req *MapRemoveRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
func (e *JSONEncoder) EncodeSharedPollRefreshRequest(req *SharedPollRefreshRequest) ([]byte, error) {
|
||||
return json.Marshal(req)
|
||||
}
|
||||
25
internal/proxyproto/generate.sh
Normal file
25
internal/proxyproto/generate.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
# go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||
# go install github.com/fatih/gomodifytags@v1.13.0
|
||||
# go install github.com/FZambia/gomodifytype@latest
|
||||
|
||||
which protoc
|
||||
which gomodifytype
|
||||
which gomodifytags
|
||||
protoc-gen-go --version
|
||||
protoc-gen-go-grpc --version
|
||||
|
||||
protoc -I ./ \
|
||||
proxy.proto \
|
||||
--go_out=. \
|
||||
--go-grpc_out=.
|
||||
|
||||
gomodifytype -file proxy.pb.go -all -w -from "[]byte" -to "Raw"
|
||||
|
||||
bash generate_tags.sh
|
||||
|
||||
echo "Done! Make sure JSON tags properly replaced for new messages"
|
||||
11
internal/proxyproto/generate_tags.sh
Normal file
11
internal/proxyproto/generate_tags.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "replacing tags of structs..."
|
||||
|
||||
gomodifytags -file proxy.pb.go -field User -struct RefreshRequest -all -w -remove-options json=omitempty >/dev/null
|
||||
gomodifytags -file proxy.pb.go -field User -struct SubscribeRequest -all -w -remove-options json=omitempty >/dev/null
|
||||
gomodifytags -file proxy.pb.go -field User -struct PublishRequest -all -w -remove-options json=omitempty >/dev/null
|
||||
gomodifytags -file proxy.pb.go -field User -struct RPCRequest -all -w -remove-options json=omitempty >/dev/null
|
||||
gomodifytags -file proxy.pb.go -field User -struct SubRefreshRequest -all -w -remove-options json=omitempty >/dev/null
|
||||
3971
internal/proxyproto/proxy.pb.go
Normal file
3971
internal/proxyproto/proxy.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
433
internal/proxyproto/proxy.proto
Normal file
433
internal/proxyproto/proxy.proto
Normal file
@@ -0,0 +1,433 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package centrifugal.centrifugo.proxy;
|
||||
|
||||
option go_package = "./;proxyproto";
|
||||
|
||||
service CentrifugoProxy {
|
||||
// Connect to proxy connection authentication and communicate initial state.
|
||||
rpc Connect(ConnectRequest) returns (ConnectResponse);
|
||||
// Refresh to proxy decision about connection expiration to the app backend.
|
||||
rpc Refresh(RefreshRequest) returns (RefreshResponse);
|
||||
// Subscribe to proxy subscription attempts to channels.
|
||||
rpc Subscribe(SubscribeRequest) returns (SubscribeResponse);
|
||||
// Publish to proxy publication attempts to channels.
|
||||
rpc Publish(PublishRequest) returns (PublishResponse);
|
||||
// RPC to execute custom logic on the backend over request through the real-time connection.
|
||||
rpc RPC(RPCRequest) returns (RPCResponse);
|
||||
// SubRefresh to proxy decision about subscription expiration to the app backend.
|
||||
rpc SubRefresh(SubRefreshRequest) returns (SubRefreshResponse);
|
||||
// SubscribeUnidirectional is an EXPERIMENTAL method which allows handling unidirectional
|
||||
// subscription streams. Stream starts with SubscribeRequest similar to Subscribe rpc,
|
||||
// then expects StreamSubscribeResponse with SubscribeResponse as first message, and
|
||||
// StreamSubscribeResponse with Publication afterwards.
|
||||
rpc SubscribeUnidirectional(SubscribeRequest) returns (stream StreamSubscribeResponse);
|
||||
// SubscribeBidirectional is an EXPERIMENTAL method which allows handling bidirectional
|
||||
// subscription streams. Stream receives StreamSubscribeRequest. First StreamSubscribeRequest
|
||||
// always contains SubscribeRequest, then StreamSubscribeRequest will contain data published
|
||||
// by client. Reverse direction works the same way as in SubscribeUnidirectional.
|
||||
rpc SubscribeBidirectional(stream StreamSubscribeRequest) returns (stream StreamSubscribeResponse);
|
||||
// NotifyCacheEmpty is an EXPERIMENTAL method which allows to load documents from the backend.
|
||||
rpc NotifyCacheEmpty(NotifyCacheEmptyRequest) returns (NotifyCacheEmptyResponse);
|
||||
// NotifyChannelState can be used to receive channel events such as channel "occupied" and "vacated".
|
||||
// This is a feature in a preview state and is only available in Centrifugo PRO.
|
||||
rpc NotifyChannelState(NotifyChannelStateRequest) returns (NotifyChannelStateResponse);
|
||||
// MapPublish to proxy map publish attempts to channels.
|
||||
rpc MapPublish(MapPublishRequest) returns (MapPublishResponse);
|
||||
// MapRemove to proxy map remove attempts from channels.
|
||||
rpc MapRemove(MapRemoveRequest) returns (MapRemoveResponse);
|
||||
// SharedPollRefresh to proxy shared poll refresh requests to the app backend.
|
||||
rpc SharedPollRefresh(SharedPollRefreshRequest) returns (SharedPollRefreshResponse);
|
||||
}
|
||||
|
||||
message FilterNode {
|
||||
string op = 1;
|
||||
string key = 2;
|
||||
string cmp = 3;
|
||||
string val = 4;
|
||||
repeated string vals = 5;
|
||||
repeated FilterNode nodes = 6;
|
||||
}
|
||||
|
||||
message Disconnect {
|
||||
reserved 3;
|
||||
uint32 code = 1;
|
||||
string reason = 2;
|
||||
}
|
||||
|
||||
message Error {
|
||||
uint32 code = 1;
|
||||
string message = 2;
|
||||
bool temporary = 3;
|
||||
}
|
||||
|
||||
message ConnectRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
bytes data = 10;
|
||||
string b64data = 11;
|
||||
string name = 12;
|
||||
string version = 13;
|
||||
repeated string channels = 14;
|
||||
}
|
||||
|
||||
message SubscribeOptions {
|
||||
int64 expire_at = 1;
|
||||
bytes info = 2;
|
||||
string b64info = 3;
|
||||
bytes data = 4;
|
||||
string b64data = 5;
|
||||
SubscribeOptionOverride override = 6;
|
||||
FilterNode server_tags_filter = 7;
|
||||
// cache_recover, when set, makes Centrifugo initiate cache recovery for the
|
||||
// server-side subscription without requiring the client to provide a recover
|
||||
// flag/position itself. This is the server-side equivalent of subscribing with an
|
||||
// empty `since` on the client. Mostly useful for unidirectional clients which do
|
||||
// not know channel names. Requires recovery to be enabled for the channel and only
|
||||
// applies in cache recovery mode, where it delivers the latest publication on
|
||||
// (re)subscribe.
|
||||
bool cache_recover = 8;
|
||||
}
|
||||
|
||||
message ConnectResult {
|
||||
string user = 1;
|
||||
int64 expire_at = 2;
|
||||
bytes info = 3;
|
||||
string b64info = 4;
|
||||
bytes data = 5;
|
||||
string b64data = 6;
|
||||
repeated string channels = 7;
|
||||
map<string, SubscribeOptions> subs = 8;
|
||||
bytes meta = 9;
|
||||
repeated ChannelsCapability caps = 10;
|
||||
// PRO only — client labels attached to the centrifuge.Client by Centrifugo PRO.
|
||||
// Parsed by OSS but not used (OSS does not populate centrifuge.ConnectReply.Labels).
|
||||
map<string, string> labels = 11;
|
||||
}
|
||||
|
||||
message ChannelsCapability {
|
||||
repeated string channels = 1;
|
||||
repeated string allow = 2;
|
||||
string match = 3;
|
||||
}
|
||||
|
||||
message ConnectResponse {
|
||||
ConnectResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message RefreshRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
bytes meta = 11;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 12;
|
||||
}
|
||||
|
||||
message RefreshResult {
|
||||
bool expired = 1;
|
||||
int64 expire_at = 2;
|
||||
bytes info = 3;
|
||||
string b64info = 4;
|
||||
bytes meta = 5;
|
||||
repeated ChannelsCapability caps = 6;
|
||||
}
|
||||
|
||||
message RefreshResponse {
|
||||
RefreshResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message SubscribeRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string channel = 11;
|
||||
string token = 12;
|
||||
bytes meta = 13;
|
||||
bytes data = 14;
|
||||
string b64data = 15;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 16;
|
||||
}
|
||||
|
||||
message BoolValue {
|
||||
bool value = 1;
|
||||
}
|
||||
|
||||
message Int32Value {
|
||||
int32 value = 1;
|
||||
}
|
||||
|
||||
message SubscribeOptionOverride {
|
||||
BoolValue presence = 1;
|
||||
BoolValue join_leave = 2;
|
||||
BoolValue force_recovery = 3;
|
||||
BoolValue force_positioning = 4;
|
||||
BoolValue force_push_join_leave = 5;
|
||||
}
|
||||
|
||||
message SubscribeResult {
|
||||
int64 expire_at = 1;
|
||||
bytes info = 2;
|
||||
string b64info = 3;
|
||||
bytes data = 4;
|
||||
string b64data = 5;
|
||||
SubscribeOptionOverride override = 6;
|
||||
repeated string allow = 7;
|
||||
FilterNode server_tags_filter = 8;
|
||||
}
|
||||
|
||||
message SubscribeResponse {
|
||||
SubscribeResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message PublishRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string channel = 11;
|
||||
bytes data = 12;
|
||||
string b64data = 13;
|
||||
bytes meta = 14;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 15;
|
||||
}
|
||||
|
||||
message PublishResult {
|
||||
bytes data = 1;
|
||||
string b64data = 2;
|
||||
bool skip_history = 3;
|
||||
map<string, string> tags = 4;
|
||||
string idempotency_key = 5;
|
||||
bool delta = 6;
|
||||
uint64 version = 7;
|
||||
string version_epoch = 8;
|
||||
}
|
||||
|
||||
message PublishResponse {
|
||||
PublishResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message MapPublishRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string channel = 11;
|
||||
string key = 12;
|
||||
bytes data = 13;
|
||||
string b64data = 14;
|
||||
bytes meta = 15;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 16;
|
||||
}
|
||||
|
||||
message MapPublishResult {
|
||||
string key = 1;
|
||||
bytes data = 2;
|
||||
string b64data = 3;
|
||||
map<string, string> tags = 4;
|
||||
int64 score = 5;
|
||||
string key_mode = 6;
|
||||
bytes stream_data = 7;
|
||||
string b64stream_data = 8;
|
||||
string idempotency_key = 9;
|
||||
bool delta = 10;
|
||||
uint64 version = 11;
|
||||
string version_epoch = 12;
|
||||
}
|
||||
|
||||
message MapPublishResponse {
|
||||
MapPublishResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message MapRemoveRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string channel = 11;
|
||||
string key = 12;
|
||||
bytes meta = 13;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 14;
|
||||
}
|
||||
|
||||
message MapRemoveResult {
|
||||
string key = 1;
|
||||
map<string, string> tags = 2;
|
||||
string idempotency_key = 3;
|
||||
}
|
||||
|
||||
message MapRemoveResponse {
|
||||
MapRemoveResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message RPCRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string method = 11;
|
||||
bytes data = 12;
|
||||
string b64data = 13;
|
||||
bytes meta = 14;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 15;
|
||||
}
|
||||
|
||||
message RPCResult {
|
||||
bytes data = 1;
|
||||
string b64data = 2;
|
||||
}
|
||||
|
||||
message RPCResponse {
|
||||
RPCResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
message SubRefreshRequest {
|
||||
string client = 1;
|
||||
string transport = 2;
|
||||
string protocol = 3;
|
||||
string encoding = 4;
|
||||
|
||||
string user = 10;
|
||||
string channel = 11;
|
||||
bytes meta = 12;
|
||||
// PRO only — connection labels attached to the originating centrifuge.Client.
|
||||
// Centrifugo PRO always populates this from Client.Labels() (no opt-in toggle).
|
||||
map<string, string> labels = 13;
|
||||
}
|
||||
|
||||
message SubRefreshResult {
|
||||
bool expired = 1;
|
||||
int64 expire_at = 2;
|
||||
bytes info = 3;
|
||||
string b64info = 4;
|
||||
}
|
||||
|
||||
message SubRefreshResponse {
|
||||
SubRefreshResult result = 1;
|
||||
Error error = 2;
|
||||
Disconnect disconnect = 3;
|
||||
}
|
||||
|
||||
// Publication is an event to be sent to a client.
|
||||
// We intentionally make it use the same Protobuf numbers for fields as our client protocol
|
||||
// Publication - for now only for consistency.
|
||||
message Publication {
|
||||
reserved 1, 2, 3, 5, 6;
|
||||
bytes data = 4;
|
||||
map<string, string> tags = 7;
|
||||
}
|
||||
|
||||
message StreamSubscribeRequest {
|
||||
// Centrifugo always sends this within the first message upon user subscription request.
|
||||
// It's always not set in the following StreamRequest messages from Centrifugo.
|
||||
SubscribeRequest subscribe_request = 1;
|
||||
// Publication may be set when client publishes to the on-demand stream. If you are using
|
||||
// bidirectional stream then Centrifugo assumes publications from client-side are allowed.
|
||||
Publication publication = 2;
|
||||
}
|
||||
|
||||
message StreamSubscribeResponse {
|
||||
// SubscribeResponse may optionally be set in the first message from backend to Centrifugo.
|
||||
SubscribeResponse subscribe_response = 1;
|
||||
// Publication goes to client. Can't be set in the first message from backend to Centrifugo.
|
||||
Publication publication = 2;
|
||||
}
|
||||
|
||||
message NotifyCacheEmptyRequest {
|
||||
string channel = 1;
|
||||
}
|
||||
|
||||
message NotifyCacheEmptyResponse {
|
||||
NotifyCacheEmptyResult result = 1;
|
||||
}
|
||||
|
||||
message NotifyCacheEmptyResult {
|
||||
bool populated = 1;
|
||||
}
|
||||
|
||||
message NotifyChannelStateRequest {
|
||||
repeated ChannelEvent events = 1;
|
||||
}
|
||||
|
||||
message ChannelEvent {
|
||||
int64 time_ms = 1;
|
||||
string channel = 2;
|
||||
string type = 3; // "occupied" | "vacated" | could be more in the future. Not using enums for better JSON interop.
|
||||
}
|
||||
|
||||
message NotifyChannelStateResponse {
|
||||
NotifyChannelStateResult result = 1;
|
||||
Error error = 2;
|
||||
}
|
||||
|
||||
message NotifyChannelStateResult {}
|
||||
|
||||
message SharedPollRefreshRequest {
|
||||
string channel = 1;
|
||||
repeated SharedPollRefreshItem items = 2;
|
||||
}
|
||||
|
||||
message SharedPollRefreshItem {
|
||||
string key = 1;
|
||||
uint64 version = 2;
|
||||
}
|
||||
|
||||
message SharedPollRefreshResult {
|
||||
repeated SharedPollRefreshResultItem items = 1;
|
||||
string epoch = 2;
|
||||
}
|
||||
|
||||
message SharedPollRefreshResultItem {
|
||||
string key = 1;
|
||||
bytes data = 2;
|
||||
uint64 version = 3;
|
||||
bool removed = 4;
|
||||
bytes prev_data = 5;
|
||||
}
|
||||
|
||||
message SharedPollRefreshResponse {
|
||||
SharedPollRefreshResult result = 1;
|
||||
Error error = 2;
|
||||
}
|
||||
615
internal/proxyproto/proxy_grpc.pb.go
Normal file
615
internal/proxyproto/proxy_grpc.pb.go
Normal file
@@ -0,0 +1,615 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v7.34.0
|
||||
// source: proxy.proto
|
||||
|
||||
package proxyproto
|
||||
|
||||
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.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
CentrifugoProxy_Connect_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/Connect"
|
||||
CentrifugoProxy_Refresh_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/Refresh"
|
||||
CentrifugoProxy_Subscribe_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/Subscribe"
|
||||
CentrifugoProxy_Publish_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/Publish"
|
||||
CentrifugoProxy_RPC_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/RPC"
|
||||
CentrifugoProxy_SubRefresh_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/SubRefresh"
|
||||
CentrifugoProxy_SubscribeUnidirectional_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/SubscribeUnidirectional"
|
||||
CentrifugoProxy_SubscribeBidirectional_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/SubscribeBidirectional"
|
||||
CentrifugoProxy_NotifyCacheEmpty_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/NotifyCacheEmpty"
|
||||
CentrifugoProxy_NotifyChannelState_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/NotifyChannelState"
|
||||
CentrifugoProxy_MapPublish_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/MapPublish"
|
||||
CentrifugoProxy_MapRemove_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/MapRemove"
|
||||
CentrifugoProxy_SharedPollRefresh_FullMethodName = "/centrifugal.centrifugo.proxy.CentrifugoProxy/SharedPollRefresh"
|
||||
)
|
||||
|
||||
// CentrifugoProxyClient is the client API for CentrifugoProxy 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 CentrifugoProxyClient interface {
|
||||
// Connect to proxy connection authentication and communicate initial state.
|
||||
Connect(ctx context.Context, in *ConnectRequest, opts ...grpc.CallOption) (*ConnectResponse, error)
|
||||
// Refresh to proxy decision about connection expiration to the app backend.
|
||||
Refresh(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error)
|
||||
// Subscribe to proxy subscription attempts to channels.
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error)
|
||||
// Publish to proxy publication attempts to channels.
|
||||
Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*PublishResponse, error)
|
||||
// RPC to execute custom logic on the backend over request through the real-time connection.
|
||||
RPC(ctx context.Context, in *RPCRequest, opts ...grpc.CallOption) (*RPCResponse, error)
|
||||
// SubRefresh to proxy decision about subscription expiration to the app backend.
|
||||
SubRefresh(ctx context.Context, in *SubRefreshRequest, opts ...grpc.CallOption) (*SubRefreshResponse, error)
|
||||
// SubscribeUnidirectional is an EXPERIMENTAL method which allows handling unidirectional
|
||||
// subscription streams. Stream starts with SubscribeRequest similar to Subscribe rpc,
|
||||
// then expects StreamSubscribeResponse with SubscribeResponse as first message, and
|
||||
// StreamSubscribeResponse with Publication afterwards.
|
||||
SubscribeUnidirectional(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamSubscribeResponse], error)
|
||||
// SubscribeBidirectional is an EXPERIMENTAL method which allows handling bidirectional
|
||||
// subscription streams. Stream receives StreamSubscribeRequest. First StreamSubscribeRequest
|
||||
// always contains SubscribeRequest, then StreamSubscribeRequest will contain data published
|
||||
// by client. Reverse direction works the same way as in SubscribeUnidirectional.
|
||||
SubscribeBidirectional(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamSubscribeRequest, StreamSubscribeResponse], error)
|
||||
// NotifyCacheEmpty is an EXPERIMENTAL method which allows to load documents from the backend.
|
||||
NotifyCacheEmpty(ctx context.Context, in *NotifyCacheEmptyRequest, opts ...grpc.CallOption) (*NotifyCacheEmptyResponse, error)
|
||||
// NotifyChannelState can be used to receive channel events such as channel "occupied" and "vacated".
|
||||
// This is a feature in a preview state and is only available in Centrifugo PRO.
|
||||
NotifyChannelState(ctx context.Context, in *NotifyChannelStateRequest, opts ...grpc.CallOption) (*NotifyChannelStateResponse, error)
|
||||
// MapPublish to proxy map publish attempts to channels.
|
||||
MapPublish(ctx context.Context, in *MapPublishRequest, opts ...grpc.CallOption) (*MapPublishResponse, error)
|
||||
// MapRemove to proxy map remove attempts from channels.
|
||||
MapRemove(ctx context.Context, in *MapRemoveRequest, opts ...grpc.CallOption) (*MapRemoveResponse, error)
|
||||
// SharedPollRefresh to proxy shared poll refresh requests to the app backend.
|
||||
SharedPollRefresh(ctx context.Context, in *SharedPollRefreshRequest, opts ...grpc.CallOption) (*SharedPollRefreshResponse, error)
|
||||
}
|
||||
|
||||
type centrifugoProxyClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCentrifugoProxyClient(cc grpc.ClientConnInterface) CentrifugoProxyClient {
|
||||
return ¢rifugoProxyClient{cc}
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) Connect(ctx context.Context, in *ConnectRequest, opts ...grpc.CallOption) (*ConnectResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ConnectResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_Connect_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) Refresh(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RefreshResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_Refresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SubscribeResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_Subscribe_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*PublishResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(PublishResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_Publish_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) RPC(ctx context.Context, in *RPCRequest, opts ...grpc.CallOption) (*RPCResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RPCResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_RPC_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) SubRefresh(ctx context.Context, in *SubRefreshRequest, opts ...grpc.CallOption) (*SubRefreshResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SubRefreshResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_SubRefresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) SubscribeUnidirectional(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamSubscribeResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &CentrifugoProxy_ServiceDesc.Streams[0], CentrifugoProxy_SubscribeUnidirectional_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[SubscribeRequest, StreamSubscribeResponse]{ClientStream: 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
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type CentrifugoProxy_SubscribeUnidirectionalClient = grpc.ServerStreamingClient[StreamSubscribeResponse]
|
||||
|
||||
func (c *centrifugoProxyClient) SubscribeBidirectional(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamSubscribeRequest, StreamSubscribeResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &CentrifugoProxy_ServiceDesc.Streams[1], CentrifugoProxy_SubscribeBidirectional_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[StreamSubscribeRequest, StreamSubscribeResponse]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type CentrifugoProxy_SubscribeBidirectionalClient = grpc.BidiStreamingClient[StreamSubscribeRequest, StreamSubscribeResponse]
|
||||
|
||||
func (c *centrifugoProxyClient) NotifyCacheEmpty(ctx context.Context, in *NotifyCacheEmptyRequest, opts ...grpc.CallOption) (*NotifyCacheEmptyResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(NotifyCacheEmptyResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_NotifyCacheEmpty_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) NotifyChannelState(ctx context.Context, in *NotifyChannelStateRequest, opts ...grpc.CallOption) (*NotifyChannelStateResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(NotifyChannelStateResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_NotifyChannelState_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) MapPublish(ctx context.Context, in *MapPublishRequest, opts ...grpc.CallOption) (*MapPublishResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(MapPublishResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_MapPublish_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) MapRemove(ctx context.Context, in *MapRemoveRequest, opts ...grpc.CallOption) (*MapRemoveResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(MapRemoveResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_MapRemove_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *centrifugoProxyClient) SharedPollRefresh(ctx context.Context, in *SharedPollRefreshRequest, opts ...grpc.CallOption) (*SharedPollRefreshResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SharedPollRefreshResponse)
|
||||
err := c.cc.Invoke(ctx, CentrifugoProxy_SharedPollRefresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CentrifugoProxyServer is the server API for CentrifugoProxy service.
|
||||
// All implementations must embed UnimplementedCentrifugoProxyServer
|
||||
// for forward compatibility.
|
||||
type CentrifugoProxyServer interface {
|
||||
// Connect to proxy connection authentication and communicate initial state.
|
||||
Connect(context.Context, *ConnectRequest) (*ConnectResponse, error)
|
||||
// Refresh to proxy decision about connection expiration to the app backend.
|
||||
Refresh(context.Context, *RefreshRequest) (*RefreshResponse, error)
|
||||
// Subscribe to proxy subscription attempts to channels.
|
||||
Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error)
|
||||
// Publish to proxy publication attempts to channels.
|
||||
Publish(context.Context, *PublishRequest) (*PublishResponse, error)
|
||||
// RPC to execute custom logic on the backend over request through the real-time connection.
|
||||
RPC(context.Context, *RPCRequest) (*RPCResponse, error)
|
||||
// SubRefresh to proxy decision about subscription expiration to the app backend.
|
||||
SubRefresh(context.Context, *SubRefreshRequest) (*SubRefreshResponse, error)
|
||||
// SubscribeUnidirectional is an EXPERIMENTAL method which allows handling unidirectional
|
||||
// subscription streams. Stream starts with SubscribeRequest similar to Subscribe rpc,
|
||||
// then expects StreamSubscribeResponse with SubscribeResponse as first message, and
|
||||
// StreamSubscribeResponse with Publication afterwards.
|
||||
SubscribeUnidirectional(*SubscribeRequest, grpc.ServerStreamingServer[StreamSubscribeResponse]) error
|
||||
// SubscribeBidirectional is an EXPERIMENTAL method which allows handling bidirectional
|
||||
// subscription streams. Stream receives StreamSubscribeRequest. First StreamSubscribeRequest
|
||||
// always contains SubscribeRequest, then StreamSubscribeRequest will contain data published
|
||||
// by client. Reverse direction works the same way as in SubscribeUnidirectional.
|
||||
SubscribeBidirectional(grpc.BidiStreamingServer[StreamSubscribeRequest, StreamSubscribeResponse]) error
|
||||
// NotifyCacheEmpty is an EXPERIMENTAL method which allows to load documents from the backend.
|
||||
NotifyCacheEmpty(context.Context, *NotifyCacheEmptyRequest) (*NotifyCacheEmptyResponse, error)
|
||||
// NotifyChannelState can be used to receive channel events such as channel "occupied" and "vacated".
|
||||
// This is a feature in a preview state and is only available in Centrifugo PRO.
|
||||
NotifyChannelState(context.Context, *NotifyChannelStateRequest) (*NotifyChannelStateResponse, error)
|
||||
// MapPublish to proxy map publish attempts to channels.
|
||||
MapPublish(context.Context, *MapPublishRequest) (*MapPublishResponse, error)
|
||||
// MapRemove to proxy map remove attempts from channels.
|
||||
MapRemove(context.Context, *MapRemoveRequest) (*MapRemoveResponse, error)
|
||||
// SharedPollRefresh to proxy shared poll refresh requests to the app backend.
|
||||
SharedPollRefresh(context.Context, *SharedPollRefreshRequest) (*SharedPollRefreshResponse, error)
|
||||
mustEmbedUnimplementedCentrifugoProxyServer()
|
||||
}
|
||||
|
||||
// UnimplementedCentrifugoProxyServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCentrifugoProxyServer struct{}
|
||||
|
||||
func (UnimplementedCentrifugoProxyServer) Connect(context.Context, *ConnectRequest) (*ConnectResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Connect not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) Refresh(context.Context, *RefreshRequest) (*RefreshResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Refresh not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Subscribe not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) Publish(context.Context, *PublishRequest) (*PublishResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Publish not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) RPC(context.Context, *RPCRequest) (*RPCResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RPC not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) SubRefresh(context.Context, *SubRefreshRequest) (*SubRefreshResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SubRefresh not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) SubscribeUnidirectional(*SubscribeRequest, grpc.ServerStreamingServer[StreamSubscribeResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeUnidirectional not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) SubscribeBidirectional(grpc.BidiStreamingServer[StreamSubscribeRequest, StreamSubscribeResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeBidirectional not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) NotifyCacheEmpty(context.Context, *NotifyCacheEmptyRequest) (*NotifyCacheEmptyResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method NotifyCacheEmpty not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) NotifyChannelState(context.Context, *NotifyChannelStateRequest) (*NotifyChannelStateResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method NotifyChannelState not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) MapPublish(context.Context, *MapPublishRequest) (*MapPublishResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method MapPublish not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) MapRemove(context.Context, *MapRemoveRequest) (*MapRemoveResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method MapRemove not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) SharedPollRefresh(context.Context, *SharedPollRefreshRequest) (*SharedPollRefreshResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SharedPollRefresh not implemented")
|
||||
}
|
||||
func (UnimplementedCentrifugoProxyServer) mustEmbedUnimplementedCentrifugoProxyServer() {}
|
||||
func (UnimplementedCentrifugoProxyServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCentrifugoProxyServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CentrifugoProxyServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCentrifugoProxyServer interface {
|
||||
mustEmbedUnimplementedCentrifugoProxyServer()
|
||||
}
|
||||
|
||||
func RegisterCentrifugoProxyServer(s grpc.ServiceRegistrar, srv CentrifugoProxyServer) {
|
||||
// If the following call panics, it indicates UnimplementedCentrifugoProxyServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&CentrifugoProxy_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_Connect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ConnectRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).Connect(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_Connect_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).Connect(ctx, req.(*ConnectRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_Refresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RefreshRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).Refresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_Refresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).Refresh(ctx, req.(*RefreshRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_Subscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubscribeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).Subscribe(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_Subscribe_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).Subscribe(ctx, req.(*SubscribeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PublishRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).Publish(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_Publish_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).Publish(ctx, req.(*PublishRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_RPC_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RPCRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).RPC(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_RPC_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).RPC(ctx, req.(*RPCRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_SubRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubRefreshRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).SubRefresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_SubRefresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).SubRefresh(ctx, req.(*SubRefreshRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_SubscribeUnidirectional_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(SubscribeRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(CentrifugoProxyServer).SubscribeUnidirectional(m, &grpc.GenericServerStream[SubscribeRequest, StreamSubscribeResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type CentrifugoProxy_SubscribeUnidirectionalServer = grpc.ServerStreamingServer[StreamSubscribeResponse]
|
||||
|
||||
func _CentrifugoProxy_SubscribeBidirectional_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(CentrifugoProxyServer).SubscribeBidirectional(&grpc.GenericServerStream[StreamSubscribeRequest, StreamSubscribeResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type CentrifugoProxy_SubscribeBidirectionalServer = grpc.BidiStreamingServer[StreamSubscribeRequest, StreamSubscribeResponse]
|
||||
|
||||
func _CentrifugoProxy_NotifyCacheEmpty_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(NotifyCacheEmptyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).NotifyCacheEmpty(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_NotifyCacheEmpty_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).NotifyCacheEmpty(ctx, req.(*NotifyCacheEmptyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_NotifyChannelState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(NotifyChannelStateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).NotifyChannelState(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_NotifyChannelState_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).NotifyChannelState(ctx, req.(*NotifyChannelStateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_MapPublish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(MapPublishRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).MapPublish(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_MapPublish_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).MapPublish(ctx, req.(*MapPublishRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_MapRemove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(MapRemoveRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).MapRemove(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_MapRemove_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).MapRemove(ctx, req.(*MapRemoveRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CentrifugoProxy_SharedPollRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SharedPollRefreshRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CentrifugoProxyServer).SharedPollRefresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CentrifugoProxy_SharedPollRefresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CentrifugoProxyServer).SharedPollRefresh(ctx, req.(*SharedPollRefreshRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// CentrifugoProxy_ServiceDesc is the grpc.ServiceDesc for CentrifugoProxy service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var CentrifugoProxy_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "centrifugal.centrifugo.proxy.CentrifugoProxy",
|
||||
HandlerType: (*CentrifugoProxyServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Connect",
|
||||
Handler: _CentrifugoProxy_Connect_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Refresh",
|
||||
Handler: _CentrifugoProxy_Refresh_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Subscribe",
|
||||
Handler: _CentrifugoProxy_Subscribe_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Publish",
|
||||
Handler: _CentrifugoProxy_Publish_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RPC",
|
||||
Handler: _CentrifugoProxy_RPC_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SubRefresh",
|
||||
Handler: _CentrifugoProxy_SubRefresh_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "NotifyCacheEmpty",
|
||||
Handler: _CentrifugoProxy_NotifyCacheEmpty_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "NotifyChannelState",
|
||||
Handler: _CentrifugoProxy_NotifyChannelState_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "MapPublish",
|
||||
Handler: _CentrifugoProxy_MapPublish_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "MapRemove",
|
||||
Handler: _CentrifugoProxy_MapRemove_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SharedPollRefresh",
|
||||
Handler: _CentrifugoProxy_SharedPollRefresh_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "SubscribeUnidirectional",
|
||||
Handler: _CentrifugoProxy_SubscribeUnidirectional_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "SubscribeBidirectional",
|
||||
Handler: _CentrifugoProxy_SubscribeBidirectional_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "proxy.proto",
|
||||
}
|
||||
25
internal/proxyproto/proxy_test.go
Normal file
25
internal/proxyproto/proxy_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package proxyproto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
msg := &RPCRequest{
|
||||
Data: []byte(`{"input": "привет"}`),
|
||||
}
|
||||
_, err := json.Marshal(msg)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMarshalProtobuf(t *testing.T) {
|
||||
msg := &RPCRequest{
|
||||
Data: []byte(`{"input": "привет"}`),
|
||||
}
|
||||
_, err := proto.Marshal(msg)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
26
internal/proxyproto/raw.go
Normal file
26
internal/proxyproto/raw.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package proxyproto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Raw type used by Centrifugo as type for fields in structs which value
|
||||
// we want to left untouched.
|
||||
type Raw []byte
|
||||
|
||||
// MarshalJSON returns *r as the JSON encoding of r.
|
||||
func (r Raw) MarshalJSON() ([]byte, error) {
|
||||
if r == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets *r to a copy of data.
|
||||
func (r *Raw) UnmarshalJSON(data []byte) error {
|
||||
if r == nil {
|
||||
return errors.New("raw: UnmarshalJSON on nil pointer")
|
||||
}
|
||||
*r = append((*r)[0:0], data...)
|
||||
return nil
|
||||
}
|
||||
8
internal/proxyproto/readme.md
Normal file
8
internal/proxyproto/readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Proxy transform rules:
|
||||
|
||||
| Client protocol type | Proxy type | Headers | Meta |
|
||||
| ------------- | ------------- | -------------- | -------------- |
|
||||
| HTTP | HTTP | In request headers | No meta |
|
||||
| GRPC | GRPC | No headers | In request meta |
|
||||
| HTTP | GRPC | In request meta | No meta |
|
||||
| GRPC | HTTP | No headers | In request headers |
|
||||
199
internal/proxyproto/shared_poll_test.go
Normal file
199
internal/proxyproto/shared_poll_test.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package proxyproto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncodeSharedPollRefreshRequest(t *testing.T) {
|
||||
encoder := &JSONEncoder{}
|
||||
req := &SharedPollRefreshRequest{
|
||||
Channel: "test:channel",
|
||||
Items: []*SharedPollRefreshItem{
|
||||
{Key: "key1", Version: 0},
|
||||
{Key: "key2", Version: 5},
|
||||
},
|
||||
}
|
||||
data, err := encoder.EncodeSharedPollRefreshRequest(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
var decoded map[string]interface{}
|
||||
err = json.Unmarshal(data, &decoded)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test:channel", decoded["channel"])
|
||||
|
||||
items := decoded["items"].([]interface{})
|
||||
require.Len(t, items, 2)
|
||||
|
||||
item0 := items[0].(map[string]interface{})
|
||||
require.Equal(t, "key1", item0["key"])
|
||||
// Version 0 should be omitted (omitempty).
|
||||
_, hasVersion := item0["version"]
|
||||
require.False(t, hasVersion)
|
||||
|
||||
item1 := items[1].(map[string]interface{})
|
||||
require.Equal(t, "key2", item1["key"])
|
||||
require.Equal(t, float64(5), item1["version"])
|
||||
}
|
||||
|
||||
func TestEncodeSharedPollRefreshRequest_EmptyItems(t *testing.T) {
|
||||
encoder := &JSONEncoder{}
|
||||
req := &SharedPollRefreshRequest{
|
||||
Channel: "ch",
|
||||
Items: []*SharedPollRefreshItem{},
|
||||
}
|
||||
data, err := encoder.EncodeSharedPollRefreshRequest(req)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(data), `"channel":"ch"`)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{
|
||||
"result": {
|
||||
"items": [
|
||||
{"key": "key1", "data": {"votes": 42}, "version": 5},
|
||||
{"key": "key2", "data": {"votes": 10}, "version": 3, "removed": true}
|
||||
]
|
||||
}
|
||||
}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.Result)
|
||||
require.Len(t, resp.Result.Items, 2)
|
||||
|
||||
item0 := resp.Result.Items[0]
|
||||
require.Equal(t, "key1", item0.Key)
|
||||
require.Equal(t, uint64(5), item0.Version)
|
||||
require.False(t, item0.Removed)
|
||||
require.Contains(t, string(item0.Data), "42")
|
||||
|
||||
item1 := resp.Result.Items[1]
|
||||
require.Equal(t, "key2", item1.Key)
|
||||
require.Equal(t, uint64(3), item1.Version)
|
||||
require.True(t, item1.Removed)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_EmptyItems(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"result": {"items": []}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.Result)
|
||||
require.Empty(t, resp.Result.Items)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_MissingFields(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"result": {"items": [{"key": "key1"}]}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.Result.Items, 1)
|
||||
item := resp.Result.Items[0]
|
||||
require.Equal(t, "key1", item.Key)
|
||||
require.Equal(t, uint64(0), item.Version)
|
||||
require.False(t, item.Removed)
|
||||
require.Nil(t, item.Data)
|
||||
require.Nil(t, item.PrevData)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_WithPrevData(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"result": {"items": [{"key": "k1", "data": {"v": 1}, "version": 2, "prev_data": {"v": 0}}]}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.Result.Items, 1)
|
||||
require.NotNil(t, resp.Result.Items[0].PrevData)
|
||||
require.Contains(t, string(resp.Result.Items[0].PrevData), "0")
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_ErrorResponse(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"error": {"code": 100, "message": "internal error"}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.Error)
|
||||
require.Equal(t, uint32(100), resp.Error.Code)
|
||||
require.Equal(t, "internal error", resp.Error.Message)
|
||||
require.Nil(t, resp.Result)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_NullResult(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"result": null}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, resp.Result)
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_InvalidJSON(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
_, err := decoder.DecodeSharedPollRefreshResponse([]byte(`not json`))
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSharedPollRefreshRequest_RoundTrip(t *testing.T) {
|
||||
encoder := &JSONEncoder{}
|
||||
decoder := &JSONDecoder{}
|
||||
|
||||
original := &SharedPollRefreshRequest{
|
||||
Channel: "test:ch",
|
||||
Items: []*SharedPollRefreshItem{
|
||||
{Key: "k1", Version: 10},
|
||||
{Key: "k2", Version: 0},
|
||||
{Key: "k3", Version: 999},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := encoder.EncodeSharedPollRefreshRequest(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Wrap in response format to test decode.
|
||||
respJSON := `{"result": {"items": [{"key": "k1", "data": {"x": 1}, "version": 11}, {"key": "k3", "data": {"x": 3}, "version": 1000}]}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(respJSON))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.Result.Items, 2)
|
||||
|
||||
// Verify the request was encoded properly.
|
||||
var reqDecoded SharedPollRefreshRequest
|
||||
err = json.Unmarshal(data, &reqDecoded)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test:ch", reqDecoded.Channel)
|
||||
require.Len(t, reqDecoded.Items, 3)
|
||||
}
|
||||
|
||||
func TestEncodeSharedPollRefreshRequest_DiffMode(t *testing.T) {
|
||||
encoder := &JSONEncoder{}
|
||||
req := &SharedPollRefreshRequest{
|
||||
Channel: "ch",
|
||||
Items: []*SharedPollRefreshItem{
|
||||
{Key: "k1", Version: 5},
|
||||
{Key: "k2", Version: 10},
|
||||
},
|
||||
}
|
||||
data, err := encoder.EncodeSharedPollRefreshRequest(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
var decoded map[string]interface{}
|
||||
err = json.Unmarshal(data, &decoded)
|
||||
require.NoError(t, err)
|
||||
|
||||
items := decoded["items"].([]interface{})
|
||||
item0 := items[0].(map[string]interface{})
|
||||
require.Equal(t, float64(5), item0["version"])
|
||||
item1 := items[1].(map[string]interface{})
|
||||
require.Equal(t, float64(10), item1["version"])
|
||||
}
|
||||
|
||||
func TestDecodeSharedPollRefreshResponse_RemovedItem(t *testing.T) {
|
||||
decoder := &JSONDecoder{}
|
||||
input := `{"result": {"items": [{"key": "k1", "removed": true}]}}`
|
||||
resp, err := decoder.DecodeSharedPollRefreshResponse([]byte(input))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.Result.Items, 1)
|
||||
require.True(t, resp.Result.Items[0].Removed)
|
||||
require.Equal(t, "k1", resp.Result.Items[0].Key)
|
||||
require.Equal(t, uint64(0), resp.Result.Items[0].Version)
|
||||
}
|
||||
Reference in New Issue
Block a user