-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for playing streams from CDN #635
base: main
Are you sure you want to change the base?
Conversation
@coderabbitai review |
✅ Actions performedReview triggered.
|
WalkthroughThe changes involve updates to the database seeding script and several UI components to incorporate new audio feed entries and attributes. The Changes
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (18)
ui/.env.production (1)
4-4
: LGTM! Consider grouping related environment variables.The addition of
NEXT_PUBLIC_AUDIO_BASE_URL
aligns well with the PR objective of adding support for playing streams from CDN. This change allows the client-side code to access the audio base URL, which is crucial for implementing CDN-based audio streaming.Consider grouping related environment variables together for better readability and maintenance. For example, you might want to place
NEXT_PUBLIC_AUDIO_BASE_URL
next toNEXT_PUBLIC_S3_BUCKET
since both are likely related to media storage/delivery.NEXT_PUBLIC_GQL_ENDPOINT=$GQL_ENDPOINT NEXT_PUBLIC_SOCKET_ENDPOINT=$SOCKET_ENDPOINT NEXT_PUBLIC_S3_BUCKET=$S3_BUCKET -NEXT_PUBLIC_AUDIO_BASE_URL=$AUDIO_BASE_URL +NEXT_PUBLIC_AUDIO_BASE_URL=$AUDIO_BASE_URL NEXT_PUBLIC_GA_ID=$GOOGLE_ANALYTICS_IDui/src/graphql/queries/getFeed.graphql (1)
16-16
: LGTM! Consider grouping related URL fields.The addition of the
cloudfrontUrl
field to thefeed
query is appropriate and aligns with the PR objective of adding support for playing streams from CDN. The change is minimal and focused, which is good for maintainability.As a minor suggestion, consider grouping related URL fields together for better readability. You might want to move
cloudfrontUrl
next to other URL fields likethumbUrl
,imageUrl
, andmapUrl
. For example:query feed($slug: String!) { feed(slug: $slug) { id name slug nodeName latLng { lat lng } introHtml thumbUrl imageUrl mapUrl cloudfrontUrl bucket } }This grouping could make it easier for developers to locate and manage URL-related fields in the future.
ui/.env.development (1)
4-4
: Great addition, aligns with PR objectives.The introduction of
NEXT_PUBLIC_AUDIO_BASE_URL
is an excellent addition that supports the PR's objective of adding CDN support for audio streams. This variable provides a centralized way to manage the base URL for audio resources, which will make it easier to switch between different environments or CDN providers in the future.Consider the following to further improve the architecture:
- Ensure that this base URL is used consistently throughout the application when constructing audio resource URLs.
- If not already implemented, consider creating a utility function that combines this base URL with resource-specific paths to generate full audio URLs. This would centralize URL construction logic and make future changes easier to manage.
ui/src/utils/urls.ts (5)
1-2
: LGTM! Consider adding input validation.The
getAudioBaseUrlFromBucket
function correctly constructs the base URL for an S3 bucket. It's concise and follows good practices by using template literals.Consider adding input validation for the
bucket
parameter to ensure it's not empty or contains invalid characters for a bucket name.
4-5
: LGTM! Consider adding input validation.The
getNodeRootUrl
function correctly constructs the node root URL by combining the base URL and node name. It's concise and uses template literals effectively.Consider adding input validation for both
audioBaseUrl
andnodeName
parameters to ensure they are not empty and have the expected format.
7-8
: LGTM! Consider adding input validation.The
getLatestTimestampUrl
function correctly constructs the URL for the 'latest.txt' file. It's concise and uses template literals effectively.Consider adding input validation for the
nodeRootUrl
parameter to ensure it's not empty and has the expected format.
10-11
: LGTM! Consider adding input validation and timestamp formatting.The
getHlsUrl
function correctly constructs the URL for the HLS stream. It's concise and uses template literals effectively.Consider the following improvements:
- Add input validation for both
nodeRootUrl
andtimestamp
parameters.- Format the
timestamp
to ensure it's in the expected format for the URL (e.g., as a UTC ISO string or Unix timestamp).Example implementation:
export const getHlsUrl = (nodeRootUrl: string, timestamp: number) => { if (!nodeRootUrl || typeof nodeRootUrl !== 'string') { throw new Error('Invalid nodeRootUrl'); } if (!Number.isFinite(timestamp)) { throw new Error('Invalid timestamp'); } const formattedTimestamp = new Date(timestamp).toISOString().replace(/[:.]/g, '-'); return `${nodeRootUrl}/hls/${formattedTimestamp}/live.m3u8`; };This example includes basic input validation and formats the timestamp as a UTC ISO string with special characters replaced by hyphens.
1-11
: Consider adding JSDoc comments for better documentation.The file is well-organized with related URL construction utility functions. Each function has a single responsibility, which is great for maintainability. To further improve the code, consider adding JSDoc comments for each function.
Here's an example of how you could document the
getHlsUrl
function:/** * Constructs the URL for accessing an HLS stream. * @param {string} nodeRootUrl - The root URL of the node. * @param {number} timestamp - The timestamp for the HLS stream. * @returns {string} The complete URL for the HLS stream. */ export const getHlsUrl = (nodeRootUrl: string, timestamp: number) => `${nodeRootUrl}/hls/${timestamp}/live.m3u8`;Adding similar documentation for all functions would greatly enhance the usability and maintainability of this utility file.
ui/src/components/layouts/MapLayout.tsx (4)
27-28
: LGTM! Consider adding a type for the returned object.The addition of
cloudfrontUrl
is a good approach for supporting CDN streams. Using an environment variable with a fallback value provides flexibility across different environments.Consider defining an interface for the object returned by
feedFromSlug
to improve type safety and documentation. For example:interface FeedData { id: string; name: string; slug: string; nodeName: string; bucket: string; cloudfrontUrl: string; latLng: { lat: number; lng: number }; } const feedFromSlug = (feedSlug: string): FeedData => ({ // ... existing properties });
36-40
: Good improvements for clarity and security. Consider memoizingfeeds
.The changes improve the code's clarity and add a layer of security by sanitizing the user-provided slug. Well done!
Consider memoizing the
feeds
array to optimize performance, especially if theuseFeedsQuery
hook is called frequently:const feeds = useMemo(() => useFeedsQuery().data?.feeds ?? [], [useFeedsQuery().data]);This ensures that the
feeds
array is only recalculated when the query data changes, potentially reducing unnecessary re-renders.
45-47
: Good use of non-null assertion with explanation. Consider using type guard.The non-null assertion resolves the TypeScript issue, and the comment explains the reasoning well.
As an alternative to using the non-null assertion operator, consider using a type guard function to assert the type of
slug
. This approach can be more type-safe:function isNonNullableString(value: string | null | undefined): value is string { return typeof value === 'string'; } // ... const feedFromQuery = useFeedQuery( { slug }, { enabled: isNonNullableString(slug) || isDynamic } );This approach eliminates the need for the non-null assertion and provides better type safety.
Line range hint
54-60
: Great optimization! Consider usinguseCallback
for map operations.The added condition to check if
feed.slug
has changed before updatingcurrentFeed
is an excellent optimization. It prevents unnecessary updates and map adjustments, potentially improving performance.To further optimize the component, consider using
useCallback
for the map operations:const updateMap = useCallback((newFeed) => { map?.setZoom(9); map?.panTo(newFeed.latLng); }, [map]); useEffect(() => { if (feed && feed.slug !== currentFeed?.slug) { setCurrentFeed(feed); updateMap(feed); } }, [feed, currentFeed, updateMap]);This approach ensures that the map update function is only recreated when the
map
object changes, potentially reducing unnecessary re-renders.ui/src/components/Player/Player.tsx (3)
45-45
: LGTM: Addition ofcloudfrontUrl
property.The
cloudfrontUrl
property has been correctly added to thecurrentFeed
type. It's good that it's marked as optional for backward compatibility.Consider adding a brief comment explaining the purpose of this new property, e.g.:
| "cloudfrontUrl" // URL for the CloudFront distribution, if applicable
51-53
: LGTM: New audio base URL logic.The new logic for determining the
audioBaseUrl
is well-implemented. It correctly prioritizes thecloudfrontUrl
when available and falls back to the bucket-based URL.For improved readability, consider extracting this logic into a separate function:
const getAudioBaseUrl = (feed: typeof currentFeed) => feed?.cloudfrontUrl ?? (feed?.bucket && getAudioBaseUrlFromBucket(feed.bucket)); const audioBaseUrl = getAudioBaseUrl(currentFeed);This would make the code more modular and easier to test.
104-104
: LGTM: Consistent use ofhlsUrl
throughout the component.The changes to use
hlsUrl
in the player options, useMemo dependencies, and useEffect hook are correct and consistent.For consistency with the rest of the codebase, consider using template literals for the console log message:
console.log(`New stream instance: ${hlsUrl}`);Also applies to: 110-110, 170-171, 177-177
server/priv/repo/seeds.exs (2)
16-84
: LGTM! Consistent feed structure with CDN support.The changes to the feeds list look good. You've successfully standardized the feed data structure and added new attributes to support CDN streaming. This is in line with the PR objectives.
A minor suggestion for improvement:
Consider extracting common values like
bucket
,bucket_region
, andcloudfront_url
into variables at the top of the script. This would make future updates easier and reduce repetition. For example:default_bucket = "audio-orcasound-net" default_bucket_region = "us-west-2" default_cloudfront_url = "https://audio.orcasound.net" feeds = [ %{ # ... other attributes bucket: default_bucket, bucket_region: default_bucket_region, cloudfront_url: default_cloudfront_url, # ... other attributes }, # ... other feeds ]This approach would make the script more maintainable and less prone to errors when updating common values in the future.
Line range hint
86-102
: Consider using environment variables for the admin password.While the admin account creation logic is functional, it's generally not recommended to hardcode passwords, even in seeding scripts. This could pose a security risk if the default password is not changed in production.
Consider using an environment variable for the admin password. This approach enhances security and follows best practices for handling sensitive information. Here's an example of how you could modify the code:
admin_password = System.get_env("ADMIN_PASSWORD") || "default_password" Orcasite.Accounts.User |> Ash.Changeset.for_create(strategy.register_action_name, %{ email: "[email protected]", password: admin_password, password_confirmation: admin_password }) # ... rest of the codeRemember to set the
ADMIN_PASSWORD
environment variable in your production environment and update your deployment documentation accordingly.ui/src/components/DetectionsTable.tsx (1)
Line range hint
1-424
: Consider component refactoring for improved maintainability.While not directly related to the current change, the
DetectionsTable
component is quite large and handles multiple responsibilities. Consider breaking it down into smaller, more focused components for improved maintainability and testability. For example:
- Extract the table rendering logic into a separate component.
- Create a dedicated component for handling notifications.
- Move the
NotificationModal
andCircularProgressWithLabel
components to separate files.Would you like assistance in planning this refactoring?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
ui/src/graphql/generated/index.ts
is excluded by!**/generated/**
📒 Files selected for processing (11)
- server/priv/repo/seeds.exs (1 hunks)
- ui/.env.development (1 hunks)
- ui/.env.production (1 hunks)
- ui/src/components/DetectionsTable.tsx (1 hunks)
- ui/src/components/Player/DetectionsPlayer.tsx (5 hunks)
- ui/src/components/Player/Player.tsx (4 hunks)
- ui/src/components/layouts/MapLayout.tsx (1 hunks)
- ui/src/graphql/queries/getCandidate.graphql (1 hunks)
- ui/src/graphql/queries/getFeed.graphql (1 hunks)
- ui/src/hooks/useTimestampFetcher.ts (4 hunks)
- ui/src/utils/urls.ts (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
ui/src/hooks/useTimestampFetcher.ts
[failure] 44-44: Server-side request forgery
The URL of this request depends on a user-provided value.
🔇 Additional comments (20)
ui/.env.development (1)
3-3
: LGTM, but verify development environment impact.The update to
NEXT_PUBLIC_S3_BUCKET
from 'dev-streaming-orcasound-net' to 'audio-orcasound-net' looks good. This change aligns the development environment with a more production-like setup, which can be beneficial for testing. However, please ensure that this change doesn't negatively impact local development workflows or cause unintended side effects.To verify the impact, please check:
- That developers can still access and test audio streams locally.
- That this change doesn't result in unexpected costs or data access issues.
- That any development-specific configurations relying on the old bucket name are updated accordingly.
ui/src/graphql/queries/getCandidate.graphql (1)
15-15
: LGTM: Addition ofcloudfrontUrl
field to thefeed
objectThe
cloudfrontUrl
field has been correctly added to thefeed
object within thecandidate
query. This addition aligns with the PR objective of adding support for playing streams from CDN.To ensure consistency across the codebase, let's verify if this field is being used in other relevant queries or mutations:
ui/src/components/layouts/MapLayout.tsx (2)
49-49
: LGTM! Consistent use ofslugFromQuery
for dynamic layouts.The updated logic for assigning
feed
correctly usesslugFromQuery
for dynamic layouts, maintaining consistency with the earlier changes in variable naming and sanitization. This change enhances the overall coherence of the component's logic.
Line range hint
1-224
: Overall, excellent improvements to the MapLayout component.The changes in this file successfully implement support for CDN streams and enhance the handling of feed data. The modifications improve clarity, security, and performance of the component. The suggestions provided in the review comments, if implemented, can further optimize the component's performance and type safety.
Great work on this update!
ui/src/components/Player/Player.tsx (3)
18-18
: LGTM: New utility function import.The import of
getAudioBaseUrlFromBucket
from@/utils/urls
is appropriate for the new audio URL generation logic.
55-57
: LGTM: UpdateduseTimestampFetcher
hook usage.The
useTimestampFetcher
hook is now correctly using the newaudioBaseUrl
along with thecurrentFeed?.nodeName
. This change aligns well with the new audio URL generation logic.
Line range hint
1-300
: Overall assessment: Well-implemented changes with minor suggestions.The changes to incorporate the new
cloudfrontUrl
property and adjust the audio URL generation logic are well-implemented. The code maintains backward compatibility and consistently uses the newhlsUrl
throughout the component. The suggestions provided are minor and aimed at improving readability and consistency.Great job on this update! The changes align well with the PR objectives and enhance the flexibility of the audio source handling.
server/priv/repo/seeds.exs (2)
Line range hint
104-285
: LGTM! Enhanced detection data for testing.The additions to the detection data look good. You've expanded the range of test data, which will be beneficial for development and testing purposes. The new entries maintain consistency with the existing structure and provide a good variety of scenarios across different feeds.
These changes will help ensure that the system can handle various types of detections across different feeds, which is crucial for thorough testing of the new CDN streaming functionality.
Line range hint
1-285
: Overall, good changes supporting CDN streaming implementation.The modifications to this seeding script align well with the PR objectives of adding support for playing streams from CDN. The standardization of feed attributes and the addition of CDN-related fields provide a solid foundation for testing the new functionality.
A few suggestions for further improvement:
- Extract common feed attributes into variables for better maintainability.
- Use environment variables for sensitive information like the admin password.
These changes will enhance the script's security and maintainability without affecting its primary purpose of seeding test data for the CDN streaming feature.
ui/src/components/DetectionsTable.tsx (1)
45-45
: LGTM! Verify usage of DetectionsTable component.The addition of
cloudfrontUrl
to thefeed
prop type is in line with the PR objective of adding CDN support. This change looks good and doesn't affect the component's internal logic.To ensure this change doesn't break existing usage of the
DetectionsTable
component, please run the following script to check its usage across the codebase:Ensure that all instances of
DetectionsTable
usage provide thecloudfrontUrl
field in thefeed
prop, and that theFeed
type definition includes this new field.ui/src/hooks/useTimestampFetcher.ts (4)
14-14
: JSDoc updated correctly for 'hlsUrl' propertyThe documentation update accurately reflects the change to the
hlsUrl
property, ensuring consistency between the code and its comments.
19-20
: JSDoc updated for 'audioBaseUrl' parameterThe function parameter documentation now correctly describes
audioBaseUrl
, which enhances code readability and maintainability.
25-25
: Function signature update improves clarityChanging the parameter from
bucket
toaudioBaseUrl
inuseTimestampFetcher
aligns with the new implementation and improves the clarity of the code.
84-84
: Return statement aligns with updated propertiesThe return statement now correctly includes
hlsUrl
, matching the changes made to the hook's logic.ui/src/components/Player/DetectionsPlayer.tsx (6)
9-13
: Imports from "@/utils/urls" are correctly addedThe required utility functions are properly imported, ensuring the component has access to the necessary URL construction utilities.
31-31
: Updated 'feed' prop to include 'cloudfrontUrl'Including
cloudfrontUrl
in thefeed
prop allows the component to utilize the CDN URL when available, enhancing flexibility in URL sourcing.
45-48
: Correctly determining 'audioBaseUrl' with fallbackThe logic appropriately uses
feed.cloudfrontUrl
if available, and falls back togetAudioBaseUrlFromBucket(feed.bucket)
when it's not, ensuring robustness in URL construction.
65-69
: Handling absence of 'hlsUrl' using a dummy URLUsing a dummy URL to trigger an error when
hlsUrl
isn't set is acceptable given the constraints of Video.js initialization, which requires a non-emptysrc
to properly handle errors.
137-138
: Development console log for 'hlsUrl' is appropriateLogging the
hlsUrl
during development aids in debugging by providing visibility into the stream instances being initialized.
144-144
: Ensure consistency in dependency arraysAs noted earlier, aligning the dependency arrays across hooks helps maintain predictable behavior. Please refer to the previous comment on line 74 for the suggested change.
const fetchTimestamp = (timestampUrl: string) => { | ||
const xhr = new XMLHttpRequest(); | ||
currentXhr = xhr; | ||
xhr.open("GET", timestampURI); | ||
xhr.open("GET", timestampUrl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential Server-Side Request Forgery (SSRF) vulnerability due to unvalidated URL input
The timestampUrl
used in xhr.open("GET", timestampUrl)
is constructed from audioBaseUrl
and nodeName
, which may be user-controlled inputs. Without proper validation, an attacker could manipulate audioBaseUrl
to make the application send requests to malicious or unintended endpoints, leading to an SSRF vulnerability.
Recommendation:
- Validate
audioBaseUrl
: Ensure thataudioBaseUrl
is validated against a whitelist of trusted domains or matches an expected pattern before it's used to construct URLs. - Use fixed endpoints if possible: If the set of legitimate
audioBaseUrl
values is known and limited, consider hardcoding these values or using a configuration that isn't directly user-controllable.
Also applies to: 59-65
🧰 Tools
🪛 GitHub Check: CodeQL
[failure] 44-44: Server-side request forgery
The URL of this request depends on a user-provided value.
type: "application/x-mpegurl", | ||
}, | ||
], | ||
}), | ||
[hlsURI, feed?.nodeName], | ||
[hlsUrl, feed?.nodeName], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of 'feed?.nodeName' in dependency array
In the useMemo
hook, the dependency array includes feed?.nodeName
, whereas in the useEffect
hook (line 144), it uses feed.nodeName
. For consistency and to prevent potential bugs, consider using the same notation in both places.
Apply this diff to make the dependency arrays consistent:
- [hlsUrl, feed?.nodeName],
+ [hlsUrl, feed.nodeName],
Committable suggestion was skipped due to low confidence.
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes
Documentation