diff options
| author | tusooa <tusooa@kazv.moe> | 2023-04-01 15:31:56 -0400 | 
|---|---|---|
| committer | tusooa <tusooa@kazv.moe> | 2023-10-15 17:20:25 -0400 | 
| commit | 844d1a14e0b4aabbb61a6693fa6dd3a0aa0dbc5b (patch) | |
| tree | 209e5fa172ce474314a3c1eeaf85b038eebf8f7a /lib | |
| parent | 314360e5e3a4bdd13f152e94050cb8562e2ea0ed (diff) | |
| download | pleroma-844d1a14e0b4aabbb61a6693fa6dd3a0aa0dbc5b.tar.gz pleroma-844d1a14e0b4aabbb61a6693fa6dd3a0aa0dbc5b.zip  | |
Start writing api docs for streaming endpoint
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/web/api_spec.ex | 10 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/streaming_operation.ex | 186 | 
2 files changed, 195 insertions, 1 deletions
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex index 2d56dc643..163226ce5 100644 --- a/lib/pleroma/web/api_spec.ex +++ b/lib/pleroma/web/api_spec.ex @@ -10,6 +10,14 @@ defmodule Pleroma.Web.ApiSpec do    @behaviour OpenApi +  defp streaming_paths do +    %{ +      "/api/v1/streaming" => %OpenApiSpex.PathItem{ +        get: Pleroma.Web.ApiSpec.StreamingOperation.streaming_operation() +      } +    } +  end +    @impl OpenApi    def spec(opts \\ []) do      %OpenApi{ @@ -45,7 +53,7 @@ defmodule Pleroma.Web.ApiSpec do          }        },        # populate the paths from a phoenix router -      paths: OpenApiSpex.Paths.from_router(Router), +      paths: Map.merge(streaming_paths(), OpenApiSpex.Paths.from_router(Router)),        components: %OpenApiSpex.Components{          parameters: %{            "accountIdOrNickname" => diff --git a/lib/pleroma/web/api_spec/operations/streaming_operation.ex b/lib/pleroma/web/api_spec/operations/streaming_operation.ex new file mode 100644 index 000000000..1ef7d72ef --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/streaming_operation.ex @@ -0,0 +1,186 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.StreamingOperation do +  alias OpenApiSpex.Operation +  alias OpenApiSpex.Response +  alias OpenApiSpex.Schema +  alias Pleroma.Web.ApiSpec.Helpers +  alias Pleroma.Web.ApiSpec.Schemas.Status + +  @spec open_api_operation(atom) :: Operation.t() +  def open_api_operation(action) do +    operation = String.to_existing_atom("#{action}_operation") +    apply(__MODULE__, operation, []) +  end + +  @spec streaming_operation() :: Operation.t() +  def streaming_operation do +    %Operation{ +      tags: ["Timelines"], +      summary: "Establish streaming connection", +      description: "Receive statuses in real-time via WebSocket.", +      security: [%{"oAuth" => ["read:statuses", "read:notifications"]}], +      parameters: [ +        Operation.parameter(:connection, :header, %Schema{type: :string}, "connection header", +          required: true +        ), +        Operation.parameter(:upgrade, :header, %Schema{type: :string}, "upgrade header", +          required: true +        ), +        Operation.parameter( +          :"sec-websocket-key", +          :header, +          %Schema{type: :string}, +          "sec-websocket-key header", +          required: true +        ), +        Operation.parameter( +          :"sec-websocket-version", +          :header, +          %Schema{type: :string}, +          "sec-websocket-version header", +          required: true +        ) +      ], +      responses: %{ +        101 => switching_protocols_response(), +        200 => +          Operation.response( +            "Server-sent events", +            "application/json", +            server_sent_events() +          ) +      } +    } +  end + +  defp switching_protocols_response do +    %Response{ +      description: "Switching protocols", +      headers: %{ +        "connection" => %OpenApiSpex.Header{required: true}, +        "upgrade" => %OpenApiSpex.Header{required: true}, +        "sec-websocket-accept" => %OpenApiSpex.Header{required: true} +      } +    } +  end + +  defp server_sent_events do +    %Schema{ +      oneOf: [ +        update_event(), +        status_update_event(), +        pleroma_respond_event() +      ] +    } +  end + +  defp stream do +    %Schema{ +      type: :array, +      title: "Stream", +      description: """ +      The stream identifier. +      The first item is the name of the stream. If the stream needs a differentiator, the second item will be the corresponding identifier. +      Currently, for the following stream types, there is a second element in the array: + +      - `list`: The second element is the id of the list, as a string. +      - `hashtag`: The second element is the name of the hashtag. +      - `public:remote:media` and `public:remote`: The second element is the domain of the corresponding instance. +      """, +      maxItems: 2, +      minItems: 1, +      items: %Schema{type: :string}, +      example: ["hashtag", "mew"] +    } +  end + +  defp get_schema(%Schema{} = schema), do: schema +  defp get_schema(schema), do: schema.schema + +  defp server_sent_event_helper(name, description, type, payload, opts \\ []) do +    payload_type = opts[:payload_type] || :json +    has_stream = opts[:has_stream] || true + +    stream_properties = +      if has_stream do +        %{stream: stream()} +      else +        %{} +      end + +    stream_example = if has_stream, do: %{"stream" => get_schema(stream()).example}, else: %{} + +    stream_required = if has_stream, do: [:stream], else: [] + +    %Schema{ +      type: :object, +      title: name, +      description: description, +      required: [:event, :payload] ++ stream_required, +      properties: +        %{ +          event: %Schema{ +            title: "Event type", +            description: "Type of the event.", +            type: :string, +            required: true, +            enum: [type] +          }, +          payload: +            if payload_type == :json do +              %Schema{ +                title: "Event payload", +                description: "JSON-encoded string of #{get_schema(payload).title}", +                allOf: [payload] +              } +            else +              payload +            end +        } +        |> Map.merge(stream_properties), +      example: +        %{ +          "event" => type, +          "payload" => get_schema(payload).example |> Jason.encode!() +        } +        |> Map.merge(stream_example) +    } +  end + +  defp update_event do +    server_sent_event_helper("New status", "A newly-posted status.", "update", Status) +  end + +  defp status_update_event do +    server_sent_event_helper("Edit", "A status that was just edited", "status.update", Status) +  end + +  defp pleroma_respond_event do +    server_sent_event_helper( +      "Server response", +      "A response to a client-sent event.", +      "pleroma:respond", +      %Schema{ +        type: :object, +        title: "Results", +        required: [:result], +        properties: %{ +          result: %Schema{ +            type: :string, +            title: "Result of the request", +            enum: ["success", "error", "ignored"] +          }, +          error: %Schema{ +            type: :string, +            title: "Error code", +            description: "An error identifier. Only appears if `result` is `error`." +          } +        }, +        example: %{"result" => "success"} +      } +    ) +  end +end  | 
