-
Notifications
You must be signed in to change notification settings - Fork 893
/
socket.ex
136 lines (107 loc) · 3.79 KB
/
socket.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
defmodule Phoenix.LiveView.Socket.AssignsNotInSocket do
@moduledoc false
defimpl Inspect do
def inspect(_, _) do
"#Phoenix.LiveView.Socket.AssignsNotInSocket<>"
end
end
defstruct [:__assigns__]
@type t :: %__MODULE__{}
end
defmodule Phoenix.LiveView.Socket do
@moduledoc """
The LiveView socket for Phoenix Endpoints.
This is typically mounted directly in your endpoint.
socket "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]]
To share an underlying transport connection between regular
Phoenix channels and LiveView processes, `use Phoenix.LiveView.Socket`
from your own `MyAppWeb.UserSocket` module.
Next, declare your `channel` definitions and optional `connect/3`, and
`id/1` callbacks to handle your channel specific needs, then mount
your own socket in your endpoint:
socket "/live", MyAppWeb.UserSocket,
websocket: [connect_info: [session: @session_options]]
If you require session options to be set at runtime, you can use
an MFA tuple. The function it designates must return a keyword list.
socket "/live", MyAppWeb.UserSocket,
websocket: [connect_info: [session: {__MODULE__, :runtime_opts, []}]]
# ...
def runtime_opts() do
Keyword.put(@session_options, :domain, host())
end
"""
use Phoenix.Socket
require Logger
@derive {Inspect,
only: [
:id,
:endpoint,
:router,
:view,
:parent_pid,
:root_pid,
:assigns,
:transport_pid
]}
defstruct id: nil,
endpoint: nil,
view: nil,
parent_pid: nil,
root_pid: nil,
router: nil,
assigns: %{__changed__: %{}},
private: %{live_temp: %{}},
fingerprints: Phoenix.LiveView.Diff.new_fingerprints(),
redirected: nil,
host_uri: nil,
transport_pid: nil
@typedoc "Struct returned when `assigns` is not in the socket."
@opaque assigns_not_in_socket :: Phoenix.LiveView.Socket.AssignsNotInSocket.t()
@typedoc "The data in a LiveView as stored in the socket."
@type assigns :: map | assigns_not_in_socket()
@type fingerprints :: {nil, map} | {binary, map}
@type t :: %__MODULE__{
id: binary(),
endpoint: module(),
view: module(),
parent_pid: nil | pid(),
root_pid: pid(),
router: module(),
assigns: assigns,
private: map(),
fingerprints: fingerprints,
redirected: nil | tuple(),
host_uri: URI.t() | :not_mounted_at_router,
transport_pid: pid() | nil
}
channel "lvu:*", Phoenix.LiveView.UploadChannel
channel "lv:*", Phoenix.LiveView.Channel
@impl Phoenix.Socket
def connect(_params, %Phoenix.Socket{} = socket, connect_info) do
{:ok, put_in(socket.private[:connect_info], connect_info)}
end
@impl Phoenix.Socket
def id(socket), do: socket.private.connect_info[:session]["live_socket_id"]
defmacro __using__(_opts) do
quote do
use Phoenix.Socket
channel "lvu:*", Phoenix.LiveView.UploadChannel
channel "lv:*", Phoenix.LiveView.Channel
def connect(params, socket, info), do: {:ok, socket}
defdelegate id(socket), to: unquote(__MODULE__)
defoverridable connect: 3, id: 1
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
quote do
defoverridable connect: 3, id: 1
def connect(params, %Phoenix.Socket{} = socket, connect_info) do
with {:ok, %Phoenix.Socket{} = new_socket} <- super(params, socket, connect_info) do
Phoenix.LiveView.Socket.connect(params, new_socket, connect_info)
end
end
end
end
end