Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/json-serializable
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
patch type="changed" "Migrate manual json serialization to json_serializable code generation"
24 changes: 24 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2024 LiveKit, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

targets:
$default:
sources:
exclude:
- example/**
builders:
json_serializable:
options:
include_if_null: false
explicit_to_json: true
8 changes: 8 additions & 0 deletions lib/src/token_source/caching.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@

import 'dart:async';

import 'package:json_annotation/json_annotation.dart';

import '../support/reusable_completer.dart';
import 'jwt.dart';
import 'token_source.dart';

part 'caching.g.dart';

/// A validator function that determines if cached credentials are still valid.
///
/// The validator receives the original request options and cached response, and should
Expand All @@ -27,6 +31,7 @@ import 'token_source.dart';
typedef TokenValidator = bool Function(TokenRequestOptions options, TokenSourceResponse response);

/// A tuple containing the request options and response that were cached.
@JsonSerializable()
class TokenStoreItem {
final TokenRequestOptions options;
final TokenSourceResponse response;
Expand All @@ -35,6 +40,9 @@ class TokenStoreItem {
required this.options,
required this.response,
});

factory TokenStoreItem.fromJson(Map<String, dynamic> json) => _$TokenStoreItemFromJson(json);
Map<String, dynamic> toJson() => _$TokenStoreItemToJson(this);
}

/// Protocol for storing and retrieving cached token credentials.
Expand Down
17 changes: 17 additions & 0 deletions lib/src/token_source/caching.g.dart

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

39 changes: 25 additions & 14 deletions lib/src/token_source/jwt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
// limitations under the License.

import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:json_annotation/json_annotation.dart';

import 'token_source.dart';

part 'jwt.g.dart';

/// Parsed payload for a LiveKit-issued JWT.
class LiveKitJwtPayload {
LiveKitJwtPayload._(this._claims);
Expand Down Expand Up @@ -114,17 +117,37 @@ class LiveKitJwtPayload {
}

/// LiveKit-specific video grants embedded within a JWT.
@JsonSerializable()
class LiveKitVideoGrant {
final String? room;

@JsonKey(name: 'room_create')
final bool? roomCreate;

@JsonKey(name: 'room_join')
final bool? roomJoin;

@JsonKey(name: 'room_list')
final bool? roomList;

@JsonKey(name: 'room_record')
final bool? roomRecord;

@JsonKey(name: 'room_admin')
final bool? roomAdmin;

@JsonKey(name: 'can_publish')
final bool? canPublish;

@JsonKey(name: 'can_subscribe')
final bool? canSubscribe;

@JsonKey(name: 'can_publish_data')
final bool? canPublishData;

@JsonKey(name: 'can_publish_sources')
final List<String>? canPublishSources;

final bool? hidden;
final bool? recorder;

Expand All @@ -143,20 +166,8 @@ class LiveKitVideoGrant {
this.recorder,
});

factory LiveKitVideoGrant.fromJson(Map<String, dynamic> json) => LiveKitVideoGrant(
room: json['room'] as String?,
roomCreate: json['room_create'] as bool?,
roomJoin: json['room_join'] as bool?,
roomList: json['room_list'] as bool?,
roomRecord: json['room_record'] as bool?,
roomAdmin: json['room_admin'] as bool?,
canPublish: json['can_publish'] as bool?,
canSubscribe: json['can_subscribe'] as bool?,
canPublishData: json['can_publish_data'] as bool?,
canPublishSources: (json['can_publish_sources'] as List?)?.map((dynamic item) => item.toString()).toList(),
hidden: json['hidden'] as bool?,
recorder: json['recorder'] as bool?,
);
factory LiveKitVideoGrant.fromJson(Map<String, dynamic> json) => _$LiveKitVideoGrantFromJson(json);
Map<String, dynamic> toJson() => _$LiveKitVideoGrantToJson(this);
}

extension TokenSourceJwt on TokenSourceResponse {
Expand Down
37 changes: 37 additions & 0 deletions lib/src/token_source/jwt.g.dart

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

32 changes: 17 additions & 15 deletions lib/src/token_source/room_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import 'package:json_annotation/json_annotation.dart';

part 'room_configuration.g.dart';

/// Configuration for dispatching an agent to a room.
@JsonSerializable()
class RoomAgentDispatch {
/// Name of the agent to dispatch.
@JsonKey(name: 'agent_name')
final String? agentName;

/// Metadata for the agent.
Expand All @@ -25,40 +31,45 @@ class RoomAgentDispatch {
this.metadata,
});

Map<String, dynamic> toJson() => {
if (agentName != null) 'agent_name': agentName,
if (metadata != null) 'metadata': metadata,
};
factory RoomAgentDispatch.fromJson(Map<String, dynamic> json) => _$RoomAgentDispatchFromJson(json);
Map<String, dynamic> toJson() => _$RoomAgentDispatchToJson(this);
}

/// Configuration for a LiveKit room.
///
/// This class contains various settings that control room behavior such as timeouts,
/// participant limits, and agent dispatching.
@JsonSerializable()
class RoomConfiguration {
/// Room name, used as ID, must be unique.
final String? name;

/// Number of seconds to keep the room open if no one joins.
@JsonKey(name: 'empty_timeout')
final int? emptyTimeout;

/// Number of seconds to keep the room open after everyone leaves.
@JsonKey(name: 'departure_timeout')
final int? departureTimeout;

/// Limit number of participants that can be in a room, excluding Egress and Ingress participants.
@JsonKey(name: 'max_participants')
final int? maxParticipants;

/// Metadata of room.
final String? metadata;

/// Minimum playout delay of subscriber.
@JsonKey(name: 'min_playout_delay')
final int? minPlayoutDelay;

/// Maximum playout delay of subscriber.
@JsonKey(name: 'max_playout_delay')
final int? maxPlayoutDelay;

/// Improves A/V sync when playout delay set to a value larger than 200ms.
/// It will disable transceiver re-use so not recommended for rooms with frequent subscription changes.
@JsonKey(name: 'sync_streams')
final bool? syncStreams;

/// Define agents that should be dispatched to this room.
Expand All @@ -76,15 +87,6 @@ class RoomConfiguration {
this.agents,
});

Map<String, dynamic> toJson() => {
if (name != null) 'name': name,
if (emptyTimeout != null) 'empty_timeout': emptyTimeout,
if (departureTimeout != null) 'departure_timeout': departureTimeout,
if (maxParticipants != null) 'max_participants': maxParticipants,
if (metadata != null) 'metadata': metadata,
if (minPlayoutDelay != null) 'min_playout_delay': minPlayoutDelay,
if (maxPlayoutDelay != null) 'max_playout_delay': maxPlayoutDelay,
if (syncStreams != null) 'sync_streams': syncStreams,
if (agents != null) 'agents': agents!.map((a) => a.toJson()).toList(),
};
factory RoomConfiguration.fromJson(Map<String, dynamic> json) => _$RoomConfigurationFromJson(json);
Map<String, dynamic> toJson() => _$RoomConfigurationToJson(this);
}
43 changes: 43 additions & 0 deletions lib/src/token_source/room_configuration.g.dart

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

Loading