115 lines
2.7 kB
1
defmodule BlueskyHose do
2
use WebSockex
3
require Logger
4
5
@table_name :reddit_links
6
7
def start_link(opts \\ []) do
8
# Create ETS table if it doesn't exist
9
:ets.new(@table_name, [:named_table, :ordered_set, :public, read_concurrency: true])
10
11
WebSockex.start_link(
12
"wss://bsky-relay.c.theo.io/subscribe?wantedCollections=app.bsky.feed.post",
13
__MODULE__,
14
:fake_state,
15
opts
16
)
17
rescue
18
ArgumentError ->
19
# Table already exists
20
WebSockex.start_link(
21
"wss://bsky-relay.c.theo.io/subscribe?wantedCollections=app.bsky.feed.post",
22
__MODULE__,
23
:fake_state,
24
opts
25
)
26
end
27
28
def handle_connect(_conn, _state) do
29
Logger.info("Connected!")
30
IO.puts("#{DateTime.utc_now()}")
31
{:ok, 0}
32
end
33
34
def handle_frame({:text, msg}, state) do
35
msg = Jason.decode!(msg)
36
37
case msg do
38
%{"commit" => record = %{"record" => %{"text" => skeet}}} = _msg ->
39
# Broadcast to the general skeet feed
40
Phoenix.PubSub.broadcast(
41
Blog.PubSub,
42
"bluesky:skeet",
43
{:new_skeet, skeet}
44
)
45
46
case contains_external_uri?(skeet, record) do
47
{:ok, link} ->
48
Phoenix.PubSub.broadcast(
49
Blog.PubSub,
50
"reddit_links",
51
{:reddit_link, link}
52
)
53
_ -> :no_nothing_no_link
54
end
55
56
57
# Broadcast to subscribers
58
59
_ ->
60
nil
61
end
62
63
{:ok, state + 1}
64
end
65
66
defp contains_external_uri?(skeet, record) when is_binary(skeet) do
67
uri =
68
case record do
69
%{
70
"record" => %{
71
"embed" => %{
72
"external" => %{
73
"uri" => uri
74
}
75
},
76
},
77
} ->
78
uri
79
_ -> nil
80
end
81
if uri do
82
if String.contains?(uri, "youtube.com") || String.contains?(uri, "youtu.be") do
83
{:ok, uri}
84
end
85
end
86
end
87
88
defp generate_id do
89
:crypto.strong_rand_bytes(10) |> Base.encode16(case: :lower)
90
end
91
92
def handle_disconnect(%{reason: {:local, reason}}, state) do
93
Logger.info("Local close with reason: #{inspect(reason)}")
94
{:ok, state}
95
end
96
97
def handle_disconnect(disconnect_map, state) do
98
super(disconnect_map, state)
99
end
100
101
# Function to get all stored Reddit links
102
def get_reddit_links(limit \\ 50) do
103
case :ets.info(@table_name) do
104
:undefined ->
105
[]
106
107
_ ->
108
:ets.tab2list(@table_name)
109
# Already sorted by key, but just to be sure
110
|> Enum.sort()
111
|> Enum.take(limit)
112
|> Enum.map(fn {_key, value} -> value end)
113
end
114
end
115
end
116