Skip to content

Commit

Permalink
api: Support ar:// source URL lookups (#1372)
Browse files Browse the repository at this point in the history
* api: Support ar:// source URL lookups

* api/playback: getByPlaybackId skip deleted assets

* api/playback: Simplify asset fetching

Keep it all in one function

* api/asset-table: Bring back opts

* .github: Run tests before coverage

* api: Fix playback ID query

* api/schema: Allow ipfs and ar schemas as input

Co-authored-by: Victor Elias <victorgelias@gmail.com>
  • Loading branch information
yondonfu and victorges authored Oct 27, 2022
1 parent 23ec9a7 commit 40910ab
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 21 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ jobs:
- name: yarn install
run: yarn install --frozen-lockfile

- name: yarn tests without coverage
run: yarn run test

- name: yarn tests with coverage
run: yarn run coverage

Expand Down
42 changes: 42 additions & 0 deletions packages/api/src/controllers/playback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,48 @@ describe("controllers/playback", () => {
const res = await client.get(`/playback/${cid}`);
expect(res.status).toBe(404);
});

it("should return playback URL assets from Arweave tx ID based on source URL lookup", async () => {
const txID = "bafyfoobar";
await db.asset.update(asset.id, {
playbackRecordingId: "mock_recording_id_2",
source: {
type: "url",
url: "ar://" + txID,
},
status: {
phase: "ready",
updatedAt: 1234,
},
});
const res = await client.get(`/playback/${txID}`);
expect(res.status).toBe(200);
await expect(res.json()).resolves.toMatchObject({
type: "vod",
meta: {
source: [
{
hrn: "HLS (TS)",
type: "html5/application/vnd.apple.mpegurl",
url: `${ingest}/recordings/mock_recording_id_2/index.m3u8`,
},
],
},
});
});

it("should return 404 for Arweave tx ID based on source URL lookup if asset is not ready", async () => {
const txID = "bafyfoobar";
await db.asset.update(asset.id, {
playbackRecordingId: "mock_recording_id_2",
source: {
type: "url",
url: "ar://" + txID,
},
});
const res = await client.get(`/playback/${txID}`);
expect(res.status).toBe(404);
});
});

describe("for recordings", () => {
Expand Down
19 changes: 7 additions & 12 deletions packages/api/src/controllers/playback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,12 @@ const newPlaybackInfo = (
},
});

const getAssetPlaybackUrl = async (
ingest: string,
id: string,
cid: boolean
) => {
const asset = cid
? (await db.asset.getByIpfsCid(id)) ??
(await db.asset.getBySourceURL("ipfs://" + id))
: await db.asset.getByPlaybackId(id);
const getAssetPlaybackUrl = async (ingest: string, id: string) => {
const asset =
(await db.asset.getByPlaybackId(id)) ??
(await db.asset.getByIpfsCid(id)) ??
(await db.asset.getBySourceURL("ipfs://" + id)) ??
(await db.asset.getBySourceURL("ar://" + id));
if (!asset || asset.deleted) {
return null;
}
Expand Down Expand Up @@ -81,9 +78,7 @@ async function getPlaybackInfo(
stream.isActive ? 1 : 0
);
}
const assetUrl =
(await getAssetPlaybackUrl(ingest, id, false)) ??
(await getAssetPlaybackUrl(ingest, id, true));
const assetUrl = await getAssetPlaybackUrl(ingest, id);
if (assetUrl) {
return newPlaybackInfo("vod", assetUrl);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/schema/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ components:
url:
type: string
format: uri
pattern: ^http(s)?://
pattern: ^(https?|ipfs|ar)://
description:
URL where the asset contents can be retrieved. Only valid for the
import task endpoint.
Expand Down
18 changes: 10 additions & 8 deletions packages/api/src/store/asset-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ export default class AssetTable extends Table<WithID<Asset>> {
playbackId: string,
opts?: QueryOptions
): Promise<WithID<Asset>> {
const res: QueryResult<DBLegacyObject> = await this.db.queryWithOpts(
sql`SELECT id, data FROM asset WHERE data->>'playbackId' = ${playbackId}`.setName(
`${this.name}_by_playbackid`
),
opts
);
if (res.rowCount < 1) {
const query = [
sql`asset.data->>'playbackId' = ${playbackId}`,
sql`asset.data->>'deleted' IS NULL`,
];
const [assets] = await this.find(query, {
...opts,
limit: 2,
});
if (assets.length < 1) {
return null;
}
return res.rows[0].data as WithID<Asset>;
return assets[0];
}

async getByIpfsCid(cid: string): Promise<WithID<Asset>> {
Expand Down

0 comments on commit 40910ab

Please sign in to comment.