@@ -5,8 +5,8 @@ defmodule RealtimeWeb.RealtimeChannel do
5
5
use RealtimeWeb , :channel
6
6
use RealtimeWeb.RealtimeChannel.Logging
7
7
8
- alias RealtimeWeb.SocketDisconnect
9
8
alias DBConnection.Backoff
9
+ alias Phoenix.Socket
10
10
11
11
alias Realtime.Crypto
12
12
alias Realtime.GenCounter
@@ -21,11 +21,15 @@ defmodule RealtimeWeb.RealtimeChannel do
21
21
alias Realtime.Tenants.Authorization.Policies.PresencePolicies
22
22
alias Realtime.Tenants.Connect
23
23
24
+ alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join
25
+ alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config
26
+ alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config.PostgresChange
24
27
alias RealtimeWeb.ChannelsAuthorization
25
28
alias RealtimeWeb.RealtimeChannel.BroadcastHandler
26
29
alias RealtimeWeb.RealtimeChannel.MessageDispatcher
27
30
alias RealtimeWeb.RealtimeChannel.PresenceHandler
28
31
alias RealtimeWeb.RealtimeChannel.Tracker
32
+ alias RealtimeWeb.SocketDisconnect
29
33
30
34
@ confirm_token_ms_interval :timer . minutes ( 5 )
31
35
@@ -46,15 +50,11 @@ defmodule RealtimeWeb.RealtimeChannel do
46
50
Logger . metadata ( external_id: tenant_id , project: tenant_id )
47
51
Logger . put_process_level ( self ( ) , log_level )
48
52
49
- socket =
50
- socket
51
- |> assign_access_token ( params )
52
- |> assign_counter ( )
53
- |> assign_presence_counter ( )
54
- |> assign ( :private? , ! ! params [ "config" ] [ "private" ] )
55
- |> assign ( :policies , nil )
53
+ # We always need to assign the access token so we can get the logs metadata working as expected
54
+ socket = assign_access_token ( socket , params )
56
55
57
- with :ok <- SignalHandler . shutdown_in_progress? ( ) ,
56
+ with { :ok , % Socket { } = socket , % Join { } = configuration } <- configure_socket ( socket , params ) ,
57
+ :ok <- SignalHandler . shutdown_in_progress? ( ) ,
58
58
:ok <- only_private? ( tenant_id , socket ) ,
59
59
:ok <- limit_joins ( socket ) ,
60
60
:ok <- limit_channels ( socket ) ,
@@ -64,7 +64,6 @@ defmodule RealtimeWeb.RealtimeChannel do
64
64
{ :ok , db_conn } <- Connect . lookup_or_start_connection ( tenant_id ) ,
65
65
{ :ok , socket } <- maybe_assign_policies ( sub_topic , db_conn , socket ) do
66
66
tenant_topic = Tenants . tenant_topic ( tenant_id , sub_topic , ! socket . assigns . private? )
67
-
68
67
# fastlane subscription
69
68
metadata =
70
69
MessageDispatcher . fastlane_metadata ( transport_pid , serializer , topic , socket . assigns . log_level , tenant_id )
@@ -73,15 +72,11 @@ defmodule RealtimeWeb.RealtimeChannel do
73
72
74
73
Phoenix.PubSub . subscribe ( Realtime.PubSub , "realtime:operations:" <> tenant_id )
75
74
76
- is_new_api = new_api? ( params )
77
- # TODO: Default will be moved to false in the future
78
- presence_enabled? =
79
- case get_in ( params , [ "config" , "presence" , "enabled" ] ) do
80
- enabled when is_boolean ( enabled ) -> enabled
81
- _ -> true
82
- end
75
+ is_new_api = new_api? ( configuration )
83
76
84
- pg_change_params = pg_change_params ( is_new_api , params , channel_pid , claims , sub_topic )
77
+ presence_enabled? = Join . presence_enabled? ( configuration )
78
+
79
+ pg_change_params = pg_change_params ( is_new_api , configuration , channel_pid , claims , sub_topic )
85
80
86
81
opts = % {
87
82
is_new_api: is_new_api ,
@@ -98,13 +93,13 @@ defmodule RealtimeWeb.RealtimeChannel do
98
93
state = % { postgres_changes: add_id_to_postgres_changes ( pg_change_params ) }
99
94
100
95
assigns = % {
101
- ack_broadcast: ! ! params [ "config" ] [ "broadcast" ] [ "ack" ] ,
96
+ ack_broadcast: Join . ack_broadcast? ( configuration ) ,
102
97
confirm_token_ref: confirm_token_ref ,
103
98
is_new_api: is_new_api ,
104
99
pg_sub_ref: nil ,
105
100
pg_change_params: pg_change_params ,
106
- presence_key: presence_key ( params ) ,
107
- self_broadcast: ! ! params [ "config" ] [ "broadcast" ] [ "self" ] ,
101
+ presence_key: Join . presence_key ( configuration ) ,
102
+ self_broadcast: Join . self_broadcast? ( configuration ) ,
108
103
tenant_topic: tenant_topic ,
109
104
channel_name: sub_topic ,
110
105
presence_enabled?: presence_enabled?
@@ -118,6 +113,9 @@ defmodule RealtimeWeb.RealtimeChannel do
118
113
119
114
{ :ok , state , assign ( socket , assigns ) }
120
115
else
116
+ { :error , :invalid_join_payload , errors , socket } ->
117
+ log_error ( socket , "InvalidJoinPayload" , errors )
118
+
121
119
{ :error , :expired_token , msg } ->
122
120
maybe_log_warning ( socket , "InvalidJWTToken" , msg )
123
121
@@ -194,6 +192,23 @@ defmodule RealtimeWeb.RealtimeChannel do
194
192
end
195
193
end
196
194
195
+ defp configure_socket ( socket , params ) do
196
+ case Join . validate ( params ) do
197
+ { :ok , configuration } ->
198
+ socket =
199
+ socket
200
+ |> assign_counter ( )
201
+ |> assign_presence_counter ( )
202
+ |> assign ( :private? , Join . private? ( configuration ) )
203
+ |> assign ( :policies , nil )
204
+
205
+ { :ok , socket , configuration }
206
+
207
+ { :error , :invalid_join_payload , errors } ->
208
+ { :error , :invalid_join_payload , errors , socket }
209
+ end
210
+ end
211
+
197
212
@ impl true
198
213
def handle_info ( :update_rate_counter , % { assigns: % { limits: % { max_events_per_second: max } } } = socket ) do
199
214
count ( socket )
@@ -531,40 +546,24 @@ defmodule RealtimeWeb.RealtimeChannel do
531
546
532
547
defp count ( % { assigns: % { rate_counter: counter } } ) , do: GenCounter . add ( counter . id )
533
548
534
- defp presence_key ( params ) do
535
- case params [ "config" ] [ "presence" ] [ "key" ] do
536
- key when is_binary ( key ) and key != "" -> key
537
- _ -> UUID . uuid1 ( )
538
- end
539
- end
540
-
541
- defp assign_access_token ( % { assigns: % { headers: headers } } = socket , params ) do
542
- access_token = Map . get ( params , "access_token" ) || Map . get ( params , "user_token" )
549
+ defp assign_access_token ( socket , params ) do
550
+ % { assigns: % { tenant_token: tenant_token , headers: headers } } = socket
543
551
{ _ , header } = Enum . find ( headers , { nil , nil } , fn { k , _ } -> k == "x-api-key" end )
544
552
545
- case access_token do
546
- nil -> assign ( socket , :access_token , header )
547
- "sb_" <> _ -> assign ( socket , :access_token , header )
548
- _ -> handle_access_token ( socket , params )
549
- end
550
- end
553
+ access_token = Map . get ( params , "access_token" )
554
+ user_token = Map . get ( params , "user_token" )
551
555
552
- defp assign_access_token ( socket , params ) , do: handle_access_token ( socket , params )
553
-
554
- defp handle_access_token ( % { assigns: % { tenant_token: _tenant_token } } = socket , % { "user_token" => user_token } )
555
- when is_binary ( user_token ) do
556
- assign ( socket , :access_token , user_token )
557
- end
556
+ access_token =
557
+ cond do
558
+ access_token != nil and ! String . starts_with? ( access_token , "sb_" ) -> access_token
559
+ user_token != nil and ! String . starts_with? ( user_token , "sb_" ) -> user_token
560
+ tenant_token != nil and ! String . starts_with? ( tenant_token , "sb_" ) -> tenant_token
561
+ true -> header
562
+ end
558
563
559
- defp handle_access_token ( % { assigns: % { tenant_token: _tenant_token } } = socket , % { "access_token" => access_token } )
560
- when is_binary ( access_token ) do
561
564
assign ( socket , :access_token , access_token )
562
565
end
563
566
564
- defp handle_access_token ( % { assigns: % { tenant_token: tenant_token } } = socket , _params ) when is_binary ( tenant_token ) do
565
- assign ( socket , :access_token , tenant_token )
566
- end
567
-
568
567
defp confirm_token ( % { assigns: assigns } ) do
569
568
% { jwt_secret: jwt_secret , access_token: access_token } = assigns
570
569
@@ -631,28 +630,30 @@ defmodule RealtimeWeb.RealtimeChannel do
631
630
} )
632
631
end
633
632
634
- defp new_api? ( % { " config" => _ } ) , do: true
633
+ defp new_api? ( % Join { config: config } ) when not is_nil ( config ) , do: true
635
634
defp new_api? ( _ ) , do: false
636
635
637
- defp pg_change_params ( true , params , channel_pid , claims , _ ) do
638
- case get_in ( params , [ "config" , " postgres_changes" ] ) do
639
- [ _ | _ ] = params_list ->
640
- params_list
641
- |> Enum . reject ( & is_nil / 1 )
642
- |> Enum . map ( fn params ->
643
- % {
644
- id: UUID . uuid1 ( ) ,
645
- channel_pid: channel_pid ,
646
- claims: claims ,
647
- params: params
648
- }
649
- end )
650
-
651
- _ ->
652
- [ ]
653
- end
636
+ defp pg_change_params ( true , % Join { config: % Config { postgres_changes: postgres_changes } } , channel_pid , claims , _ )
637
+ when not is_nil ( postgres_changes ) do
638
+ postgres_changes
639
+ |> Enum . reject ( & is_nil / 1 )
640
+ |> Enum . map ( fn % PostgresChange { table: table , event: event , schema: schema , filter: filter } ->
641
+ params =
642
+ % { "table" => table , "filter" => filter , "schema" => schema , "event" => event }
643
+ |> Enum . reject ( fn { _ , v } -> is_nil ( v ) end )
644
+ |> Map . new ( )
645
+
646
+ % {
647
+ id: UUID . uuid1 ( ) ,
648
+ channel_pid: channel_pid ,
649
+ claims: claims ,
650
+ params: params
651
+ }
652
+ end )
654
653
end
655
654
655
+ defp pg_change_params ( true , _ , _ , _ , _ ) , do: [ ]
656
+
656
657
defp pg_change_params ( false , _ , channel_pid , claims , sub_topic ) do
657
658
params =
658
659
case String . split ( sub_topic , ":" , parts: 3 ) do
0 commit comments