129 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
defmodule WebSock do
 | 
						|
  @external_resource Path.join([__DIR__, "../README.md"])
 | 
						|
 | 
						|
  @moduledoc @external_resource
 | 
						|
             |> File.read!()
 | 
						|
             |> String.split("<!-- MDOC -->")
 | 
						|
             |> Enum.fetch!(1)
 | 
						|
 | 
						|
  @typedoc "The type of an implementing module"
 | 
						|
  @type impl :: module()
 | 
						|
 | 
						|
  @typedoc "The type of state passed into / returned from `WebSock` callbacks"
 | 
						|
  @type state :: term()
 | 
						|
 | 
						|
  @typedoc "Possible data frame types"
 | 
						|
  @type data_opcode :: :text | :binary
 | 
						|
 | 
						|
  @typedoc "Possible control frame types"
 | 
						|
  @type control_opcode :: :ping | :pong
 | 
						|
 | 
						|
  @typedoc "All possible frame types"
 | 
						|
  @type opcode :: data_opcode() | control_opcode()
 | 
						|
 | 
						|
  @typedoc "The structure of an outbound message"
 | 
						|
  @type message :: {opcode(), iodata() | nil}
 | 
						|
 | 
						|
  @typedoc "Convenience type for one or many outbound messages"
 | 
						|
  @type messages :: message() | [message()]
 | 
						|
 | 
						|
  @typedoc "The result as returned from init, handle_in, handle_control & handle_info calls"
 | 
						|
  @type handle_result ::
 | 
						|
          {:push, messages(), state()}
 | 
						|
          | {:reply, term(), messages(), state()}
 | 
						|
          | {:ok, state()}
 | 
						|
          | {:stop, {:shutdown, :restart} | term(), state()}
 | 
						|
          | {:stop, term(), close_detail(), state()}
 | 
						|
          | {:stop, term(), close_detail(), messages(), state()}
 | 
						|
 | 
						|
  @typedoc "Details about why a connection was closed"
 | 
						|
  @type close_reason :: :normal | :remote | :shutdown | :timeout | {:error, term()}
 | 
						|
 | 
						|
  @typedoc "Describes the data to send in a connection close frame"
 | 
						|
  @type close_detail :: integer() | {integer(), iodata() | nil}
 | 
						|
 | 
						|
  @doc """
 | 
						|
  Called by WebSock after a WebSocket connection has been established (that is, after the server
 | 
						|
  has accepted the connection & the WebSocket handshake has been successfully completed).
 | 
						|
  Implementations can use this callback to perform tasks such as subscribing the client to any
 | 
						|
  relevant subscriptions within the application, or any other task which should be undertaken at
 | 
						|
  the time the connection is established
 | 
						|
 | 
						|
  The return value from this callback is handled as described in `c:handle_in/2`
 | 
						|
  """
 | 
						|
  @callback init(term()) :: handle_result()
 | 
						|
 | 
						|
  @doc """
 | 
						|
  Called by WebSock when a frame is received from the client. WebSock will only call this function
 | 
						|
  once a complete frame has been received (that is, once any continuation frames have been
 | 
						|
  received).
 | 
						|
 | 
						|
  The return value from this callback are processed as follows:
 | 
						|
 | 
						|
  * `{:push, messages(), state()}`: The indicated message(s) are sent to the client. The
 | 
						|
    indicated state value is used to update the socket's current state
 | 
						|
  * `{:reply, term(), messages(), state()}`: The indicated message(s) are sent to the client. The
 | 
						|
    indicated state value is used to update the socket's current state. The second element of the
 | 
						|
    tuple has no semantic meaning in this context and is ignored. This return tuple is included
 | 
						|
    here solely for backwards compatibility with the `Phoenix.Socket.Transport` behaviour; it is in
 | 
						|
    all respects semantically identical to the `{:push, ...}` return value previously described
 | 
						|
  * `{:ok, state()}`: The indicated state value is used to update the socket's current state
 | 
						|
  * `{:stop, reason :: term(), state()}`: The connection will be closed based on the indicated
 | 
						|
    reason. If `reason` is `:normal`, `c:terminate/2` will be called with a `reason` value of
 | 
						|
    `:normal`. If the `reason` is `{:shutdown, :restart}`, the server is restarting and
 | 
						|
    the WebSocket adapter should close with the `1012` Service Restart code.
 | 
						|
    In all other cases, it will be called with `{:error, reason}`. Server
 | 
						|
    implementations should also use this value when determining how to close the connection with
 | 
						|
    the client
 | 
						|
  * `{:stop, reason :: term(), close_detail(), state()}`: Similar to the previous clause, but allows
 | 
						|
    for the explicit setting of either a plain close code or a close code with a body to be sent to
 | 
						|
    the client
 | 
						|
  * `{:stop, reason :: term(), close_detail(), messages(), state()}`: Similar to the previous clause, but allows
 | 
						|
    for the sending of one or more frames before sending the connection close frame to the client
 | 
						|
  """
 | 
						|
  @callback handle_in({binary(), opcode: data_opcode()}, state()) :: handle_result()
 | 
						|
 | 
						|
  @doc """
 | 
						|
  Called by WebSock when a ping or pong frame has been received from the client. Note that
 | 
						|
  implementations SHOULD NOT send a pong frame in response; this MUST be automatically done by the
 | 
						|
  web server before this callback has been called.
 | 
						|
 | 
						|
  Despite the name of this callback, it is not called for connection close frames even though they
 | 
						|
  are technically control frames. WebSock will handle any received connection
 | 
						|
  close frames and issue calls to `c:terminate/2` as / if appropriate
 | 
						|
 | 
						|
  This callback is optional
 | 
						|
 | 
						|
  The return value from this callback is handled as described in `c:handle_in/2`
 | 
						|
  """
 | 
						|
  @callback handle_control({binary(), opcode: control_opcode()}, state()) :: handle_result()
 | 
						|
 | 
						|
  @doc """
 | 
						|
  Called by WebSock when the socket process receives a `c:GenServer.handle_info/2` call which was
 | 
						|
  not otherwise processed by the server implementation.
 | 
						|
 | 
						|
  The return value from this callback is handled as described in `c:handle_in/2`
 | 
						|
  """
 | 
						|
  @callback handle_info(term(), state()) :: handle_result()
 | 
						|
 | 
						|
  @doc """
 | 
						|
  Called by WebSock when a connection is closed. `reason` may be one of the following:
 | 
						|
 | 
						|
  * `:normal`: The local end shut down the connection normally, by returning a `{:stop, :normal,
 | 
						|
    state()}` tuple from one of the `WebSock.handle_*` callbacks
 | 
						|
  * `:remote`: The remote end shut down the connection
 | 
						|
  * `:shutdown`: The local server is being shut down
 | 
						|
  * `:timeout`: No data has been sent or received for more than the configured timeout duration
 | 
						|
  * `{:error, reason}`: An error occurred. This may be the result of error
 | 
						|
    handling in the local server, or the result of a `WebSock.handle_*` callback returning a `{:stop,
 | 
						|
    reason, state}` tuple where reason is any value other than `:normal`
 | 
						|
 | 
						|
  This callback is optional
 | 
						|
 | 
						|
  The return value of this callback is ignored
 | 
						|
  """
 | 
						|
  @callback terminate(reason :: close_reason(), state()) :: any()
 | 
						|
 | 
						|
  @optional_callbacks handle_control: 2, terminate: 2
 | 
						|
end
 |