Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ku1ik committed Aug 26, 2023
2 parents 7018519 + 41d6fdb commit a3a8035
Show file tree
Hide file tree
Showing 33 changed files with 332 additions and 62 deletions.
3 changes: 2 additions & 1 deletion assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import css from '../css/app.scss';
import $ from 'jquery';
import "bootstrap";
import "phoenix_html";
import { createPlayer } from './player';
import { createPlayer, cinemaHeight } from './player';

window.createPlayer = createPlayer;
window.cinemaHeight = cinemaHeight;

$(function() {
$('input[data-behavior=focus]:first').focus().select();
Expand Down
14 changes: 12 additions & 2 deletions assets/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ export function createPlayer(src, container, opts) {
if (opts.customTerminalFontFamily) {
opts.terminalFontFamily = `${opts.customTerminalFontFamily},Consolas,Menlo,'Bitstream Vera Sans Mono',monospace,'Powerline Symbols'`;

document.fonts.load(`1em ${opts.customTerminalFontFamily}`).then(() => {
return document.fonts.load(`1em ${opts.customTerminalFontFamily}`).then(() => {
console.log(`loaded font ${opts.customTerminalFontFamily}`);
create(src, container, opts);
return create(src, container, opts);
}).catch(error => {
console.log(`failed to load font ${opts.customTerminalFontFamily}`, error);
return create(src, container, opts);
Expand All @@ -15,3 +15,13 @@ export function createPlayer(src, container, opts) {
return create(src, container, opts);
}
}

const CONTAINER_VERTICAL_PADDING = 2 * 4;
const APPROX_CHAR_WIDTH = 7;
const APPROX_CHAR_HEIGHT = 16;

export function cinemaHeight(cols, rows) {
const ratio = (rows * APPROX_CHAR_HEIGHT) / (cols * APPROX_CHAR_WIDTH);
const height = Math.round(CONTAINER_VERTICAL_PADDING + 100 * ratio);
return `${height}vw`;
}
18 changes: 11 additions & 7 deletions assets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"asciinema-player": "^3.5.0",
"asciinema-player": "next",
"babel-loader": "^8.3.0",
"bootstrap": "^4.5.0",
"copy-webpack-plugin": "^11.0.0",
Expand Down
16 changes: 14 additions & 2 deletions lib/asciinema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,27 @@ defmodule Asciinema do
defdelegate verify_login_token(token), to: Accounts

def merge_accounts(src_user, dst_user) do
Repo.transaction(fn ->
Repo.transact(fn ->
Recordings.reassign_asciicasts(src_user.id, dst_user.id)
Streaming.reassign_live_streams(src_user.id, dst_user.id)
Accounts.reassign_api_tokens(src_user.id, dst_user.id)
Accounts.delete_user!(src_user)
Accounts.get_user(dst_user.id)

{:ok, Accounts.get_user(dst_user.id)}
end)
end

def delete_user!(user) do
result =
Repo.transact(fn ->
Recordings.delete_asciicasts(user)
Streaming.delete_live_streams(user)
Accounts.delete_user!(user)
end)

with {:ok, _} <- result, do: :ok
end

defdelegate get_live_stream(id_or_owner), to: Streaming

def recording_gc_days do
Expand Down
15 changes: 13 additions & 2 deletions lib/asciinema/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ defmodule Asciinema.Accounts do

def get_user(id), do: Repo.get(User, id)

def find_user_by_username(username) do
Repo.one(
from(u in User,
where: fragment("lower(?)", u.username) == ^String.downcase(username)
)
)
end

def find_user_by_auth_token(auth_token) do
Repo.get_by(User, auth_token: auth_token)
end
Expand Down Expand Up @@ -120,11 +128,11 @@ defmodule Asciinema.Accounts do
end
end

def lookup_user(identifier) do
def lookup_user(identifier) when is_binary(identifier) do
if String.contains?(identifier, "@") do
{:email, Repo.get_by(User, email: identifier)}
else
{:username, Repo.get_by(User, username: identifier)}
{:username, find_user_by_username(identifier)}
end
end

Expand Down Expand Up @@ -304,6 +312,9 @@ defmodule Asciinema.Accounts do
end

def delete_user!(%User{} = user) do
Repo.delete_all(assoc(user, :api_tokens))
Repo.delete!(user)

:ok
end
end
2 changes: 2 additions & 0 deletions lib/asciinema/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ defmodule Asciinema.Application do

# List all child processes to be supervised
children = [
# Start task supervisor
{Task.Supervisor, name: Asciinema.TaskSupervisor},
# Start cluster supervisor
{Cluster.Supervisor, [topologies, [name: Asciinema.ClusterSupervisor]]},
# Start the PubSub system
Expand Down
12 changes: 10 additions & 2 deletions lib/asciinema/recordings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule Asciinema.Recordings do
|> Repo.preload(:user)
end

def public_asciicasts(%{asciicasts: _} = owner, limit \\ 4) do
def list_public_asciicasts(%{asciicasts: _} = owner, limit \\ 4) do
owner
|> Ecto.assoc(:asciicasts)
|> filter(:public)
Expand All @@ -47,7 +47,7 @@ defmodule Asciinema.Recordings do
|> Repo.all()
end

def other_public_asciicasts(asciicast, limit \\ 4) do
def list_other_public_asciicasts(asciicast, limit \\ 4) do
Asciicast
|> filter({asciicast.user_id, :public})
|> where([a], a.id != ^asciicast.id)
Expand Down Expand Up @@ -492,6 +492,14 @@ defmodule Asciinema.Recordings do
end
end

def delete_asciicasts(%{asciicasts: _} = owner) do
for a <- Repo.all(Ecto.assoc(owner, :asciicasts)) do
{:ok, _} = delete_asciicast(a)
end

:ok
end

def update_snapshot(%Asciicast{} = asciicast) do
cols = asciicast.cols_override || asciicast.cols
rows = asciicast.rows_override || asciicast.rows
Expand Down
14 changes: 14 additions & 0 deletions lib/asciinema/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ defmodule Asciinema.Repo do

use Scrivener, page_size: 10

def transact(fun, opts \\ []) do
transaction(
fn ->
case fun.() do
{:ok, value} -> value
:ok -> :transaction_commited
{:error, reason} -> rollback(reason)
:error -> rollback(:transaction_rollback_error)
end
end,
opts
)
end

def count(query) do
aggregate(query, :count, :id)
end
Expand Down
6 changes: 6 additions & 0 deletions lib/asciinema/streaming.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ defmodule Asciinema.Streaming do
end
end

def delete_live_streams(%{live_streams: _} = owner) do
Repo.delete_all(Ecto.assoc(owner, :live_streams))

:ok
end

def reassign_live_streams(src_user_id, dst_user_id) do
from(s in LiveStream, where: s.user_id == ^src_user_id)
|> Repo.update_all(set: [user_id: dst_user_id, updated_at: Timex.now()])
Expand Down
1 change: 1 addition & 0 deletions lib/asciinema/streaming/live_stream.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ defmodule Asciinema.Streaming.LiveStream do
field :current_viewer_count, :integer
field :peak_viewer_count, :integer
field :buffer_time, :float
field :parser, :string

timestamps()

Expand Down
22 changes: 18 additions & 4 deletions lib/asciinema/streaming/live_stream_server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ defmodule Asciinema.Streaming.LiveStreamServer do
state = reset_stream(state, vt_size, stream_time)

if vt_init do
:ok = Vt.feed(state.vt, vt_init)
Vt.feed(state.vt, vt_init)
end

publish(state.stream_id, :stream, %Update{
Expand All @@ -117,15 +117,22 @@ defmodule Asciinema.Streaming.LiveStreamServer do
end

def handle_call({:feed, {time, data} = event}, {pid, _} = _from, %{producer: pid} = state) do
:ok = Vt.feed(state.vt, data)
new_size = Vt.feed(state.vt, data)

publish(state.stream_id, :stream, %Update{
stream_id: state.stream_id,
event: :feed,
data: event
})

{:reply, :ok, %{state | last_stream_time: time, last_feed_time: Timex.now()}}
state = %{
state
| last_stream_time: time,
last_feed_time: Timex.now(),
vt_size: new_size || state.vt_size
}

{:reply, :ok, state}
end

def handle_call({:feed, _event}, _from, state) do
Expand Down Expand Up @@ -168,7 +175,14 @@ defmodule Asciinema.Streaming.LiveStreamServer do

def handle_info(:update_stream, state) do
Process.send_after(self(), :update_stream, @update_stream_interval)
stream = Streaming.update_live_stream(state.stream, current_viewer_count: state.viewer_count)
{cols, rows} = state.vt_size

stream =
Streaming.update_live_stream(state.stream,
current_viewer_count: state.viewer_count,
cols: cols,
rows: rows
)

{:noreply, %{state | stream: stream}}
end
Expand Down
15 changes: 15 additions & 0 deletions lib/asciinema/streaming/parser/alis.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ defmodule Asciinema.Streaming.Parser.Alis do
{:ok, [feed: {time, data}], state}
end

def parse(
{
<<
?r,
time::little-float-32,
cols::little-16,
rows::little-16
>>,
_opts
},
%{status: :online} = state
) do
{:ok, [resize: {time, {cols, rows}}], state}
end

def parse({<<0x04>>, _opts}, %{status: status} = state) when status in [:init, :online] do
{:ok, [status: :offline], %{state | status: :offline}}
end
Expand Down
8 changes: 8 additions & 0 deletions lib/asciinema/streaming/parser/json.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ defmodule Asciinema.Streaming.Parser.Json do
{:ok, [feed: {time, data}], state}
end

def handle_message([time, "r", data], state) when is_number(time) and is_binary(data) do
[cols, rows] = String.split(data, "x")
cols = String.to_integer(cols)
rows = String.to_integer(rows)

{:ok, [resize: {time, {cols, rows}}], state}
end

def handle_message([time, type, data], state)
when is_number(time) and is_binary(type) and is_binary(data) do
{:ok, [], state}
Expand Down
2 changes: 1 addition & 1 deletion lib/asciinema/vt.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule Asciinema.Vt do
# => {:ok, vt} | {:error, :invalid_size}

def feed(_vt, _str), do: :erlang.nif_error(:nif_not_loaded)
# => :ok
# => nil | {cols, rows}

def dump(_vt), do: :erlang.nif_error(:nif_not_loaded)
# => ...
Expand Down
7 changes: 7 additions & 0 deletions lib/asciinema_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ defmodule AsciinemaWeb do
end
end

def json do
quote do
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end

def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
Expand Down
17 changes: 7 additions & 10 deletions lib/asciinema_web/controllers/live_stream/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -195,24 +195,21 @@ script -f -O live.pipe</code></pre>
</section>

<script>
window.addEventListener('load', function() {
window.addEventListener('load', async function() {
const container = document.getElementById('cinema');
const opts = <%= safe_json(player_opts(@stream, @player_opts)) %>;
const player = window.createPlayer(
const player = await window.createPlayer(
<%= safe_json(player_src(@stream)) %>,
container,
{ ...opts, fit: 'both', logger: console }
);
const containerVerticalPadding = 2 * 4;
const approxCharWidth = 7;
const approxCharHeight = 16;
function resizeCinema({ cols, rows }) {
container.style.height = window.cinemaHeight(cols, rows);
}
player.addEventListener('reset', ({ cols, rows }) => {
const ratio = (rows * approxCharHeight) / (cols * approxCharWidth);
const height = Math.round(containerVerticalPadding + 100 * ratio);
container.style.height = `${height}vw`;
});
player.addEventListener('reset', resizeCinema);
player.addEventListener('resize', resizeCinema);
});
</script>
Loading

0 comments on commit a3a8035

Please sign in to comment.