Skip to content

Commit 25ef2b7

Browse files
committed
initial of TMDBAlexa
1 parent b530495 commit 25ef2b7

File tree

17 files changed

+690
-0
lines changed

17 files changed

+690
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Amazon.Lambda.Core;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
5+
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
6+
7+
namespace TMDBAlexa.SeedData;
8+
9+
public class Function
10+
{
11+
private readonly LambdaEntryPoint _entryPoint;
12+
13+
public Function()
14+
{
15+
var startup = new Startup();
16+
IServiceProvider provider = startup.Setup();
17+
18+
_entryPoint = provider.GetRequiredService<LambdaEntryPoint>();
19+
}
20+
21+
public async Task<string> FunctionHandler(ILambdaContext context)
22+
{
23+
return await _entryPoint.Handler();
24+
}
25+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Amazon.DynamoDBv2.Model;
2+
using Amazon.DynamoDBv2;
3+
using Microsoft.Extensions.Logging;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using TMDbLib.Client;
10+
using Microsoft.Extensions.Configuration;
11+
using TMDBAlexa.Shared;
12+
13+
namespace TMDBAlexa.SeedData
14+
{
15+
public class LambdaEntryPoint
16+
{
17+
private readonly ILogger<LambdaEntryPoint> _logger;
18+
private readonly DynamoDBService _dbService;
19+
private readonly IConfiguration _config;
20+
public LambdaEntryPoint(ILogger<LambdaEntryPoint> logger, DynamoDBService dbService, IConfiguration config)
21+
{
22+
_logger = logger;
23+
_dbService = dbService;
24+
_config = config;
25+
}
26+
27+
public async Task<string> Handler()
28+
{
29+
_logger.LogInformation("Handler invoked");
30+
31+
TMDbClient client = new TMDbClient(_config["TMDBApiKey"]);
32+
33+
await _dbService.CreateTable();
34+
35+
for (int i = 1; i < 100; i++)
36+
{
37+
var results = await client.GetMoviePopularListAsync("en-US", i);
38+
39+
await _dbService.WriteToTable(results);
40+
}
41+
42+
return "Done";
43+
}
44+
}
45+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"profiles": {
3+
"Mock Lambda Test Tool": {
4+
"commandName": "Executable",
5+
"commandLineArgs": "--port 5050",
6+
"workingDirectory": ".\\bin\\$(Configuration)\\net6.0",
7+
"executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe"
8+
}
9+
}
10+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Amazon.DynamoDBv2;
2+
using Amazon.Extensions.NETCore.Setup;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Logging;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
using TMDBAlexa.Shared;
12+
13+
namespace TMDBAlexa.SeedData
14+
{
15+
public class Startup
16+
{
17+
public IServiceProvider Setup()
18+
{
19+
var configuration = new ConfigurationBuilder()
20+
.SetBasePath(Directory.GetCurrentDirectory())
21+
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
22+
.AddEnvironmentVariables()
23+
.Build();
24+
25+
var services = new ServiceCollection();
26+
27+
services.AddSingleton<IConfiguration>(configuration);
28+
29+
services.AddLogging(loggingBuilder =>
30+
{
31+
loggingBuilder.ClearProviders();
32+
});
33+
34+
35+
ConfigureServices(configuration, services);
36+
37+
IServiceProvider provider = services.BuildServiceProvider();
38+
39+
return provider;
40+
}
41+
42+
private void ConfigureServices(IConfiguration configuration, ServiceCollection services)
43+
{
44+
AWSOptions awsOptions = configuration.GetAWSOptions();
45+
services.AddDefaultAWSOptions(awsOptions);
46+
services.AddAWSService<IAmazonDynamoDB>();
47+
48+
services.AddSingleton<LambdaEntryPoint, LambdaEntryPoint>();
49+
services.AddSingleton<DynamoDBService, DynamoDBService>();
50+
}
51+
}
52+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net6.0</TargetFramework>
4+
<ImplicitUsings>enable</ImplicitUsings>
5+
<Nullable>enable</Nullable>
6+
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
7+
<AWSProjectType>Lambda</AWSProjectType>
8+
<!-- This property makes the build directory similar to a publish directory and helps the AWS .NET Lambda Mock Test Tool find project dependencies. -->
9+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
10+
<!-- Generate ready to run images during publishing to improve cold start time. -->
11+
<PublishReadyToRun>true</PublishReadyToRun>
12+
</PropertyGroup>
13+
<ItemGroup>
14+
<PackageReference Include="Amazon.Lambda.Core" Version="2.1.0" />
15+
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.3.0" />
16+
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.3.66" />
17+
<PackageReference Include="AWSSDK.Extensions.NETCore.Setup" Version="3.7.2" />
18+
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
19+
20+
<PackageReference Include="TMDbLib" Version="1.9.2" />
21+
22+
<!-- Packages required for Configuration -->
23+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
24+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
25+
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
26+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
27+
<!---->
28+
29+
<!-- Packages required for Logging -->
30+
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
31+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
32+
</ItemGroup>
33+
<ItemGroup>
34+
<ProjectReference Include="..\TMDBAlexa.Shared\TMDBAlexa.Shared.csproj" />
35+
</ItemGroup>
36+
<ItemGroup>
37+
<None Update="appsettings.json">
38+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
39+
</None>
40+
</ItemGroup>
41+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"TMDBApiKey": ""
3+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
{
3+
"Information" : [
4+
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
5+
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
6+
"dotnet lambda help",
7+
"All the command line options for the Lambda command can be specified in this file."
8+
],
9+
"profile" : "default",
10+
"region" : "us-west-2",
11+
"configuration" : "Release",
12+
"function-runtime" : "dotnet6",
13+
"function-memory-size" : 256,
14+
"function-timeout" : 30,
15+
"function-handler" : "TMDBAlexa.SeedData::TMDBAlexa.SeedData.Function::FunctionHandler",
16+
"framework" : "net6.0",
17+
"function-name" : "TMDBAlexaSeedData",
18+
"package-type" : "Zip",
19+
"function-role" : "arn:aws:iam::563011967245:role/lambda_exec_TMDBAlexaSeedData",
20+
"function-architecture" : "x86_64",
21+
"function-subnets" : "",
22+
"function-security-groups" : "",
23+
"tracing-mode" : "PassThrough",
24+
"environment-variables" : "",
25+
"image-tag" : "",
26+
"function-description" : ""
27+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using Amazon.DynamoDBv2;
2+
using Amazon.DynamoDBv2.DataModel;
3+
using Amazon.DynamoDBv2.Model;
4+
using Microsoft.Extensions.Logging;
5+
using TMDbLib.Objects.General;
6+
using TMDbLib.Objects.Search;
7+
8+
namespace TMDBAlexa.Shared
9+
{
10+
public class DynamoDBService
11+
{
12+
private readonly ILogger<DynamoDBService> _logger;
13+
private readonly AmazonDynamoDBClient _client = new AmazonDynamoDBClient();
14+
private readonly string _tableName = "movies";
15+
16+
public DynamoDBService(ILogger<DynamoDBService> logger)
17+
{
18+
_logger = logger;
19+
}
20+
21+
public async Task<MovieModel> SearchTable(string searchText)
22+
{
23+
DynamoDBContext context = new DynamoDBContext(_client);
24+
25+
var conditions = new List<ScanCondition>()
26+
{
27+
new ScanCondition("TitleLower", Amazon.DynamoDBv2.DocumentModel.ScanOperator.Contains, searchText.ToLower())
28+
};
29+
30+
var queryResult = await context.ScanAsync<MovieModel>(conditions).GetRemainingAsync();
31+
32+
if (queryResult.Count > 0)
33+
{
34+
return queryResult.FirstOrDefault();
35+
}
36+
return null;
37+
}
38+
39+
public async Task CreateTable()
40+
{
41+
await DeleteTable();
42+
var request = new CreateTableRequest
43+
{
44+
AttributeDefinitions = new List<AttributeDefinition>()
45+
{
46+
new AttributeDefinition
47+
{
48+
AttributeName = "id",
49+
AttributeType = "N"
50+
},
51+
new AttributeDefinition
52+
{
53+
AttributeName = "popularity",
54+
AttributeType = "N"
55+
}
56+
},
57+
KeySchema = new List<KeySchemaElement>
58+
{
59+
new KeySchemaElement
60+
{
61+
AttributeName = "id",
62+
KeyType = "HASH" //Partition key
63+
},
64+
new KeySchemaElement
65+
{
66+
AttributeName = "popularity",
67+
KeyType = "RANGE" //Sort key
68+
}
69+
},
70+
ProvisionedThroughput = new ProvisionedThroughput
71+
{
72+
ReadCapacityUnits = 5,
73+
WriteCapacityUnits = 6
74+
},
75+
TableName = _tableName
76+
};
77+
78+
var response = await _client.CreateTableAsync(request);
79+
80+
var tableDescription = response.TableDescription;
81+
_logger.LogInformation("{1}: {0} \t ReadsPerSec: {2} \t WritesPerSec: {3}",
82+
tableDescription.TableStatus,
83+
tableDescription.TableName,
84+
tableDescription.ProvisionedThroughput.ReadCapacityUnits,
85+
tableDescription.ProvisionedThroughput.WriteCapacityUnits);
86+
87+
string status = tableDescription.TableStatus;
88+
_logger.LogInformation(_tableName + " - " + status);
89+
90+
await WaitUntilTableReady(_tableName);
91+
}
92+
93+
public async Task WriteToTable(SearchContainer<SearchMovie> results)
94+
{
95+
DynamoDBContext context = new DynamoDBContext(_client);
96+
97+
BatchWrite<MovieModel> model = context.CreateBatchWrite<MovieModel>();
98+
99+
foreach (var movie in results.Results)
100+
{
101+
model.AddPutItem(new MovieModel
102+
{
103+
Id = movie.Id,
104+
Overview = movie.Overview,
105+
Popularity = movie.Popularity,
106+
ReleaseDate = movie.ReleaseDate.ToString(),
107+
Title = movie.Title,
108+
TitleLower = movie.Title.ToLower(),
109+
VoteAverage = movie.VoteAverage,
110+
VoteCount = movie.VoteCount
111+
});
112+
}
113+
114+
await model.ExecuteAsync();
115+
}
116+
117+
private async Task DeleteTable()
118+
{
119+
try
120+
{
121+
await _client.DescribeTableAsync(new DescribeTableRequest
122+
{
123+
TableName = _tableName
124+
});
125+
126+
DeleteTableRequest deleteRequest = new DeleteTableRequest
127+
{
128+
TableName = _tableName
129+
};
130+
131+
await _client.DeleteTableAsync(deleteRequest);
132+
133+
Thread.Sleep(5000);
134+
}
135+
catch (ResourceNotFoundException)
136+
{ }
137+
}
138+
139+
private async Task WaitUntilTableReady(string tableName)
140+
{
141+
string status = null;
142+
// Let us wait until table is created. Call DescribeTable.
143+
do
144+
{
145+
System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
146+
try
147+
{
148+
var res = await _client.DescribeTableAsync(new DescribeTableRequest
149+
{
150+
TableName = tableName
151+
});
152+
153+
_logger.LogInformation("Table name: {0}, status: {1}",
154+
res.Table.TableName,
155+
res.Table.TableStatus);
156+
status = res.Table.TableStatus;
157+
}
158+
catch (ResourceNotFoundException)
159+
{
160+
// DescribeTable is eventually consistent. So you might
161+
// get resource not found. So we handle the potential exception.
162+
}
163+
} while (status != "ACTIVE");
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)