зеркало из
1
0
Форкнуть 0

Visual Object sample and deployment templates that show scaleout and upgrade.

This commit is contained in:
Vipul Modi 2018-05-06 00:55:14 -07:00
Родитель ec8453416d
Коммит 5d2dea281e
41 изменённых файлов: 27694 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,8 @@
.dockerignore
.env
.git
.gitignore
.vs
.vscode
*/bin
*/obj

Просмотреть файл

@ -0,0 +1,84 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text;
[DataContract]
public sealed class Color
{
public static double[][] CurrentColorsPalette =
{
new[] {0.0, 0.0, 1.0, 0.0},
new[] {0.0, 1.0, 0.0, 0.0},
new[] {1.0, 0.0, 0.0, 0.0}
};
public static double[][] HistoryColorsPalette =
{
new[] {1.0, 0.0, 0.0, 0.0},
new[] {1.0, 1.0, 0.0, 0.0},
new[] {1.0, 1.0, 1.0, 0.0}
};
public Color(double r, double g, double b, double a)
{
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
public Color(Color other)
{
this.R = other.R;
this.G = other.G;
this.B = other.B;
this.A = other.A;
}
[DataMember]
public double R { get; private set; }
[DataMember]
public double G { get; private set; }
[DataMember]
public double B { get; private set; }
[DataMember]
public double A { get; private set; }
public static Color CreateRandom(double[][] colorPalette, Random rand = null)
{
if (rand == null)
{
rand = new Random((int) DateTime.Now.Ticks);
}
int colorIndex = rand.Next(colorPalette.GetLength(0));
return new Color(
r: colorPalette[colorIndex][0] + rand.NextDouble(),
g: colorPalette[colorIndex][1] + rand.NextDouble(),
b: colorPalette[colorIndex][2] + rand.NextDouble(),
a: colorPalette[colorIndex][3] + rand.NextDouble());
}
public void ToJson(StringBuilder builder)
{
builder.AppendFormat(
"{{ \"r\":{0}, \"g\":{1}, \"b\":{2}, \"a\":{3} }}",
this.R.ToString(NumberFormatInfo.InvariantInfo),
this.G.ToString(NumberFormatInfo.InvariantInfo),
this.B.ToString(NumberFormatInfo.InvariantInfo),
this.A.ToString(NumberFormatInfo.InvariantInfo));
}
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text;
[DataContract]
public sealed class Coordinate
{
public Coordinate(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public Coordinate(Coordinate other)
{
this.X = other.X;
this.Y = other.Y;
this.Z = other.Z;
}
[DataMember]
public double X { get; private set; }
[DataMember]
public double Y { get; private set; }
[DataMember]
public double Z { get; private set; }
public static Coordinate CreateRandom(Random rand = null)
{
if (rand == null)
{
rand = new Random((int) DateTime.Now.Ticks);
}
return new Coordinate(rand.NextDouble(), rand.NextDouble(), rand.NextDouble());
}
public string ToJson()
{
StringBuilder sb = new StringBuilder();
this.ToJson(sb);
return sb.ToString();
}
public void ToJson(StringBuilder builder)
{
builder.AppendFormat(
"{{ \"x\":{0}, \"y\":{1}, \"z\":{2} }}",
this.X.ToString(NumberFormatInfo.InvariantInfo),
this.Y.ToString(NumberFormatInfo.InvariantInfo),
this.Z.ToString(NumberFormatInfo.InvariantInfo));
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
public interface IVisualObjectsBox
{
string GetJson();
void SetObject(string objectId, string objectJson);
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
using System;
using System.Runtime.Serialization;
[DataContract]
public class Speed
{
public Speed(Speed other)
{
this.XSpeed = other.XSpeed;
this.YSpeed = other.YSpeed;
this.ZSpeed = other.ZSpeed;
}
public Speed(double x, double y, double z)
{
this.XSpeed = x;
this.YSpeed = y;
this.ZSpeed = z;
}
[DataMember]
public double XSpeed { get; private set; }
[DataMember]
public double YSpeed { get; private set; }
[DataMember]
public double ZSpeed { get; private set; }
public static Speed CreateRandom(Random rand = null)
{
if (rand == null)
{
rand = new Random((int) DateTime.Now.Ticks);
}
return new Speed(rand.NextDouble()*0.05, rand.NextDouble()*0.05, rand.NextDouble()*0.05);
}
}
}

Просмотреть файл

@ -0,0 +1,201 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
[DataContract]
public class VisualObject
{
private const int HistoryLength = 7;
public VisualObject(string name, Speed speed, Coordinate location, Color color, Color historyColor, double rotation = 0)
{
this.Name = name;
this.Speed = speed;
this.CurrentLocation = location;
this.CurrentColor = color;
this.HistoryColor = historyColor;
this.Rotation = rotation;
this.LocationHistory = new List<Coordinate>();
this.HistoryStartIndex = -1;
}
public VisualObject(VisualObject other)
{
this.Name = other.Name;
this.Speed = new Speed(other.Speed);
this.CurrentLocation = new Coordinate(other.CurrentLocation);
this.LocationHistory = new List<Coordinate>(other.LocationHistory.Count);
foreach (Coordinate c in other.LocationHistory)
{
this.LocationHistory.Add(new Coordinate(c));
}
this.CurrentColor = new Color(other.CurrentColor);
this.HistoryColor = new Color(other.HistoryColor);
this.Rotation = other.Rotation;
}
[DataMember]
public string Name { get; private set; }
[DataMember]
public Speed Speed { get; private set; }
[DataMember(Name = "current")]
public Coordinate CurrentLocation { get; set; }
[DataMember]
public Color CurrentColor { get; set; }
[DataMember]
public Color HistoryColor { get; set; }
[DataMember]
public int HistoryStartIndex { get; set; }
[DataMember(Name = "history")]
public List<Coordinate> LocationHistory { get; private set; }
[DataMember]
public double Rotation { get; set; }
public static VisualObject CreateRandom(string name, Random rand = null)
{
if (rand == null)
{
rand = new Random(name.GetHashCode());
}
return new VisualObject(
name,
Speed.CreateRandom(rand),
Coordinate.CreateRandom(rand),
Color.CreateRandom(Color.CurrentColorsPalette, rand),
Color.CreateRandom(Color.HistoryColorsPalette, rand));
}
public void Move(bool rotate)
{
if (this.LocationHistory.Count < HistoryLength)
{
this.HistoryStartIndex = (this.HistoryStartIndex + 1);
this.LocationHistory.Add(new Coordinate(this.CurrentLocation));
}
else
{
this.HistoryStartIndex = (this.HistoryStartIndex + 1)%HistoryLength;
this.LocationHistory[this.HistoryStartIndex] = new Coordinate(this.CurrentLocation);
}
double xSpeed = this.Speed.XSpeed;
double ySpeed = this.Speed.YSpeed;
double zSpeed = this.Speed.ZSpeed;
double x = this.CurrentLocation.X + xSpeed;
double y = this.CurrentLocation.Y + ySpeed;
double z = this.CurrentLocation.Z + zSpeed;
this.CurrentLocation = new Coordinate(this.CurrentLocation.X + xSpeed, this.CurrentLocation.Y + ySpeed, this.CurrentLocation.Z + zSpeed);
// trim to edges
this.Speed = new Speed(
CheckForEdge(x, xSpeed),
CheckForEdge(y, ySpeed),
CheckForEdge(z, zSpeed));
if (rotate)
{
this.Rotation = 5;
}
else
{
this.Rotation = 0;
}
}
public string ToJson()
{
StringBuilder sb = new StringBuilder();
this.ToJson(sb);
return sb.ToString();
}
public void ToJson(StringBuilder builder)
{
builder.Append("{");
{
builder.Append("\"current\":");
this.CurrentLocation.ToJson(builder);
}
{
builder.Append(", \"history\":");
builder.Append("[");
int currentIndex = this.HistoryStartIndex;
if (currentIndex != -1)
{
bool first = true;
do
{
currentIndex++;
if (currentIndex == this.LocationHistory.Count)
{
currentIndex = 0;
}
if (first)
{
first = false;
}
else
{
builder.Append(", ");
}
this.LocationHistory[currentIndex].ToJson(builder);
} while (currentIndex != this.HistoryStartIndex);
}
builder.Append("]");
}
{
builder.Append(", \"currentColor\":");
this.CurrentColor.ToJson(builder);
}
{
builder.Append(", \"historyColor\":");
this.HistoryColor.ToJson(builder);
}
{
builder.Append(", \"rotation\":");
builder.Append(this.Rotation);
}
builder.Append("}");
}
private static double CheckForEdge(double point, double speed)
{
if (point < -1.0 || point > 1.0)
{
return speed*-1.0;
}
return speed;
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
</Project>

Просмотреть файл

@ -0,0 +1,113 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Common
{
using System;
using System.Collections.Concurrent;
using System.Threading;
public class VisualObjectsBox : IVisualObjectsBox
{
private readonly ConcurrentDictionary<string, string> objectData;
private readonly ConcurrentDictionary<string, Timer> expiryTimers;
private readonly TimeSpan expiryInterval;
private readonly Timer refreshTimer;
private string currentJson;
public VisualObjectsBox()
: this(Timeout.InfiniteTimeSpan, TimeSpan.FromMilliseconds(10))
{
}
public VisualObjectsBox(TimeSpan expiryInterval, TimeSpan refreshInterval)
{
this.expiryInterval = expiryInterval;
if (expiryInterval != Timeout.InfiniteTimeSpan)
{
this.expiryTimers = new ConcurrentDictionary<string, Timer>();
}
else
{
this.expiryTimers = null;
}
this.objectData = new ConcurrentDictionary<string, string>();
this.currentJson = "[]";
this.refreshTimer = new Timer(
new TimerCallback(this.RefreshJson),
null,
refreshInterval,
refreshInterval);
}
string IVisualObjectsBox.GetJson()
{
return this.currentJson;
}
void IVisualObjectsBox.SetObject(string objectId, string objectJson)
{
if (this.expiryTimers != null)
{
if (this.expiryTimers.TryGetValue(objectId, out Timer expiryTimer))
{
ExtendExpiryTimer(expiryTimer);
}
else
{
this.expiryTimers.AddOrUpdate(objectId,
this.CreateExpiryTimer(objectId),
(i, t) => ExtendExpiryTimer(t));
}
}
this.objectData[objectId] = "{\"id\":\"" + objectId + "\", \"node\":" + objectJson + "}";
}
private void RemoveObject(string objectId)
{
if (this.expiryTimers != null)
{
this.expiryTimers.TryRemove(objectId, out Timer timer);
}
this.objectData.TryRemove(objectId, out string objectJson);
}
private Timer ExtendExpiryTimer(Timer t)
{
t.Change(expiryInterval, Timeout.InfiniteTimeSpan);
return t;
}
private void OnObjectExpired(object state)
{
string objectId = (string)state;
RemoveObject(objectId);
}
private void RefreshJson(object state)
{
if (this.objectData.Keys.Count > 0)
{
this.currentJson = "[" + String.Join(",", this.objectData.Values) + "]";
}
else
{
this.currentJson = "[]";
}
}
private Timer CreateExpiryTimer(string objectId)
{
return new Timer(
new TimerCallback(OnObjectExpired),
objectId,
this.expiryInterval,
Timeout.InfiniteTimeSpan);
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2043
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9B56FCB0-63B4-404F-8A09-42EF52B53347}") = "VisualObjects", "VisualObjects\VisualObjects.sfaproj", "{F3713D3C-FEB8-4951-BCFF-63606F992E52}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "web", "web\web.csproj", "{AF13B73E-E661-4BBD-90A5-5FD6752E8ACA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualObjects.Common", "VisualObjects.Common\VisualObjects.Common.csproj", "{FAAA707B-1F39-4D77-B2FD-0E2BEE6F7D7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "worker", "worker\worker.csproj", "{DE9FB102-B975-4841-9828-58493D68F2E2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F3713D3C-FEB8-4951-BCFF-63606F992E52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3713D3C-FEB8-4951-BCFF-63606F992E52}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3713D3C-FEB8-4951-BCFF-63606F992E52}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3713D3C-FEB8-4951-BCFF-63606F992E52}.Release|Any CPU.Build.0 = Release|Any CPU
{AF13B73E-E661-4BBD-90A5-5FD6752E8ACA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF13B73E-E661-4BBD-90A5-5FD6752E8ACA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF13B73E-E661-4BBD-90A5-5FD6752E8ACA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF13B73E-E661-4BBD-90A5-5FD6752E8ACA}.Release|Any CPU.Build.0 = Release|Any CPU
{FAAA707B-1F39-4D77-B2FD-0E2BEE6F7D7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAAA707B-1F39-4D77-B2FD-0E2BEE6F7D7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAAA707B-1F39-4D77-B2FD-0E2BEE6F7D7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAAA707B-1F39-4D77-B2FD-0E2BEE6F7D7C}.Release|Any CPU.Build.0 = Release|Any CPU
{DE9FB102-B975-4841-9828-58493D68F2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE9FB102-B975-4841-9828-58493D68F2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE9FB102-B975-4841-9828-58493D68F2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE9FB102-B975-4841-9828-58493D68F2E2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0329D31B-D1EA-4A8C-B679-C79993DD4B4A}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,4 @@
application:
schemaVersion: 0.0.1
name: VisualObjects
description: VisualObjects description.

Просмотреть файл

@ -0,0 +1,13 @@
## Network definition ##
network:
schemaVersion: 0.0.1
name: VisualObjectsNetwork
description: VisualObjectsNetwork description.
addressPrefix: 10.0.0.4/22
ingressConfig:
layer4:
- name: webIngress
publicPort: 80
applicationName: VisualObjects
serviceName: web
endpointName: webListener

Просмотреть файл

@ -0,0 +1,3 @@
## Visual Studio SFApp Publish Profile ##
vsSFAppPublishProfile:
schemaVersion: 0.0.1

Просмотреть файл

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.SFApp.Sdk">
<PropertyGroup Label="Globals">
<ProjectGuid>f3713d3c-feb8-4951-bcff-63606f992e52</ProjectGuid>
<SFApplicationProjectVersion>0.3.0</SFApplicationProjectVersion>
<SFApplicationTargetsVersion>0.3.0</SFApplicationTargetsVersion>
<SFApplicationToolingVersion>0.6.0.0</SFApplicationToolingVersion>
</PropertyGroup>
<ItemGroup>
<None Include="App Resources\app.yaml" />
<None Include="App Resources\network.yaml" />
<None Include="Publish Profiles\cloud.yaml" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,6 @@
docker build . -f web\Dockerfile -t seabreeze/azure-mesh-visualobjects-web:1.0-nanoserver-1709
docker build . -f worker\Dockerfile -t seabreeze/azure-mesh-visualobjects-worker:1.0-nanoserver-1709
docker build . -f worker\rotate.Dockerfile -t seabreeze/azure-mesh-visualobjects-worker:1.0-rotate-nanoserver-1709
docker push seabreeze/azure-mesh-visualobjects-web:1.0-nanoserver-1709
docker push seabreeze/azure-mesh-visualobjects-worker:1.0-nanoserver-1709
docker push seabreeze/azure-mesh-visualobjects-worker:1.0-rotate-nanoserver-1709

Просмотреть файл

@ -0,0 +1,3 @@
docker build . -f web\Dockerfile
docker build . -f worker\Dockerfile
docker build . -f worker\rotate.Dockerfile

Просмотреть файл

@ -0,0 +1,49 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Web.Controllers
{
using System.IO;
using Microsoft.AspNetCore.Mvc;
using VisualObjects.Common;
[Route("api/[controller]")]
public class ValuesController : Controller
{
private IVisualObjectsBox objectBox;
public ValuesController(IVisualObjectsBox objectBox)
{
this.objectBox = objectBox;
}
// GET api/values/getjson
[HttpGet("{id}")]
public string getjson()
{
return this.objectBox.GetJson();
}
// POST api/values
[HttpPost]
public ActionResult Post([FromQuery]string id)
{
var host = this.HttpContext.Request.Host;
var req = this.HttpContext.Request;
var jsonData = string.Empty;
using (StreamReader reader = new StreamReader(req.Body))
{
jsonData = reader.ReadToEnd();
}
this.objectBox.SetObject(id, jsonData);
return Ok();
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 8080
FROM microsoft/aspnetcore-build:2.0 AS build
WORKDIR /src
COPY web/web.csproj web/
RUN dotnet restore web/web.csproj
COPY . .
WORKDIR /src/web
RUN dotnet build web.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish web.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "web.dll"]

Просмотреть файл

@ -0,0 +1,24 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Web
{
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
}
}

Просмотреть файл

@ -0,0 +1,26 @@
## Service definition ##
application:
schemaVersion: 0.0.1
name: VisualObjects
services:
- name: web
description: web description.
osType: Windows
codePackages:
- name: web
image: web:dev
endpoints:
- name: webListener
port: 20005
environmentVariables:
- name: ASPNETCORE_URLS
value: http://+:80
# - name: ApplicationInsights:InstrumentationKey
# value: "<Place AppInsights key here, or reference it via a secret>"
resources:
requests:
cpu: 0.5
memoryInGB: 1
replicaCount: 1
networkRefs:
- name: VisualObjectsNetwork

Просмотреть файл

@ -0,0 +1,128 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Web
{
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using VisualObjects.Common;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IVisualObjectsBox>(CreateVisualObjectsBox());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
app.UseWebSockets(webSocketOptions);
app.Use(async (context, next) =>
{
if (context.Request.Path == "/data")
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await SendData(context, webSocket, app.ApplicationServices.GetService<IVisualObjectsBox>());
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
}
private async Task SendData(HttpContext context, WebSocket webSocket, IVisualObjectsBox objectBox)
{
using (webSocket)
{
while (true)
{
byte[] buffer = Encoding.UTF8.GetBytes(objectBox.GetJson());
try
{
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, buffer.Length),
WebSocketMessageType.Text,
true,
CancellationToken.None);
if (webSocket.State != WebSocketState.Open)
{
break;
}
}
catch (WebSocketException)
{
// If the browser quit or the socket was closed, exit this loop so we can get a new browser socket.
break;
}
// wait a bit and continue. This determines the client refresh rate.
await Task.Delay(TimeSpan.FromMilliseconds(10), CancellationToken.None);
}
}
}
private static IVisualObjectsBox CreateVisualObjectsBox()
{
TimeSpan refreshInterval = TimeSpan.FromMilliseconds(10);
if (long.TryParse(Environment.GetEnvironmentVariable("BOX_REFRESH_INTERVAL_MILLIS"), out long refreshIntervalMillis))
{
refreshInterval = TimeSpan.FromMilliseconds(refreshIntervalMillis);
}
TimeSpan expiryInterval = TimeSpan.FromMilliseconds(10000);
if (long.TryParse(Environment.GetEnvironmentVariable("BOX_EXPIRY_INTERVAL_MILLIS"), out long expiryIntervalMillis))
{
expiryInterval = TimeSpan.FromMilliseconds(expiryIntervalMillis);
}
Console.WriteLine("Creating box with Expiry = " + expiryInterval + ", Refresh = " + refreshInterval);
return new VisualObjectsBox(expiryInterval, refreshInterval);
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.VisualStudio.Azure.SFApp.Targets" Version="0.6.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VisualObjects.Common\VisualObjects.Common.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,20 @@
<html>
<head>
<title>Microsoft Azure Service Fabric Visual Objects Demo</title>
<script type="text/javascript" src="Scripts/visualobjects.js"></script>
<script type="text/javascript" src="Scripts/paper-full.js"></script>
<style type="text/css">
body {
background-color: black;
}
canvas {
width: 99%;
height: 98%;
}
</style>
</head>
<body onload="startDrawing();">
<canvas id="canvas" resize keepalive="true"> </canvas>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

37
samples/src/visualobjects/web/wwwroot/scripts/paper-core.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

38
samples/src/visualobjects/web/wwwroot/scripts/paper-full.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,199 @@
var newDataReceived = false;
var jsonData = "";
var triangles = new Array();
var triangleHistories = new Array();
function onNewDataReceived(jsonString) {
jsonData = jsonString;
newDataReceived = true;
}
function drawScene() {
if (newDataReceived) {
var newNodes = null;
try {
newNodes = JSON.parse(jsonData);
}
catch (err) {
newNodes = null;
}
if (newNodes == null) {
return;
}
var numNewNodes = newNodes.length;
var newNodesTracker = new Array();
for (newNodesIndex = 0; newNodesIndex < numNewNodes; ++newNodesIndex) {
var newNodeEntry = newNodes[newNodesIndex];
newNodesTracker[newNodeEntry.id] = newNodeEntry.node;
var currentTriangle = triangles[newNodeEntry.id];
if (currentTriangle == null) {
// new object
// create new triangle
createTriangles(newNodeEntry);
} else {
// existing oject
// update existing triangle
updateTriangles(newNodeEntry);
}
}
if (Object.keys(triangles).length != numNewNodes) {
// remove the extra nodes
var newTriangles = new Array();
var newTriangleHistories = new Array();
for (var key in triangles) {
if (triangles.hasOwnProperty(key)) {
if (newNodesTracker[key] == null) {
removeTriangles(key);
} else {
newTriangles[key] = triangles[key];
newTriangleHistories[key] = triangleHistories[key];
}
}
}
triangles = newTriangles;
triangleHistories = newTriangleHistories;
}
// wait for the new data to be received before repainting
newDataReceived = false;
}
}
function createTriangles(nodeEntry) {
var nodeId = nodeEntry.id;
var node = nodeEntry.node;
var t = new Path.RegularPolygon(new Point(0, 0), 3, 20);
t.fillColor = new Color(node.currentColor.r, node.currentColor.g, node.currentColor.b);
triangles[nodeId] = t;
var numHistory = node.history.length;
triangleHistories[nodeId] = new Array();
for (historyEntry = 0; historyEntry < numHistory; ++historyEntry) {
var h = new Path.RegularPolygon(new Point(0, 0), 3, (20 - (2 * (numHistory - historyEntry))));
h.fillColor = new Color(node.currentColor.r, node.currentColor.g, node.currentColor.b);
h.fillColor.alpha = 1 - (0.11 * (numHistory - historyEntry));
triangleHistories[nodeId][historyEntry] = h;
}
}
function removeTriangles(nodeId) {
var t = triangles[nodeId];
t.fillColor = 'black';
t.remove();
if (triangleHistories[nodeId] != null) {
var histories = triangleHistories[nodeId];
var numHistory = histories.length;
for (historyEntry = 0; historyEntry < numHistory; ++historyEntry) {
var h = triangleHistories[nodeId][historyEntry];
h.fillColor = 'black';
h.remove();
}
}
}
function updateTriangles(nodeEntry) {
var nodeId = nodeEntry.id;
var node = nodeEntry.node;
triangles[nodeId].position = scalePosToViewport(node.current.x, node.current.y);
triangles[nodeId].rotation = node.rotation;
var numHistory = node.history.length;
var currentHistoryCount = Object.keys(triangleHistories[nodeId]).length;
if (numHistory != currentHistoryCount) {
// remove existing history and recreate the history
for (historyEntry = 0; historyEntry < currentHistoryCount; ++historyEntry) {
var historyTriangle = triangleHistories[nodeId][historyEntry];
historyTriangle.currentColor = 'black';
historyTriangle.remove();
}
triangleHistories[nodeId] = new Array();
for (historyEntry = 0; historyEntry < numHistory; ++historyEntry) {
var h = new Path.RegularPolygon(new Point(0, 0), 3, (20 - (2 * (numHistory - historyEntry))));
h.fillColor = new Color(node.currentColor.r, node.currentColor.g, node.currentColor.b);
h.fillColor.alpha = 1 - (0.11 * (numHistory - historyEntry));
triangleHistories[nodeId][historyEntry] = h;
}
} else {
// update history
for (historyEntry = 0; historyEntry < numHistory; ++historyEntry) {
var historyNodeData = node.history[historyEntry];
var historyTriangle = triangleHistories[nodeId][historyEntry];
historyTriangle.position = scalePosToViewport(historyNodeData.x, historyNodeData.y);
historyTriangle.rotation = node.rotation;
}
}
}
function scalePosToViewport(nodex, nodey) {
var xfactor = view.viewSize.width / 2;
var yfactor = view.viewSize.height / 2;
var xval = nodex + 1;
var yval = nodey + 1;
//scaling factor is width or height over 2.
//2 = width or height, 0 = 0;
return new Point(xval * xfactor, yval * yfactor);
}
function startDrawing() {
var canvas = document.getElementById("canvas");
canvas.style.border = "#00ff00 3px solid";
paper.install(window);
paper.setup('canvas');
initWebSocket();
view.onFrame = function (event) {
drawScene();
}
}
var websocket;
function initWebSocket() {
websocket = new WebSocket("ws://" + window.location.host + "/data");
websocket.onopen = function () { };
websocket.onmessage = function (args) {
onNewDataReceived(args.data);
};
websocket.onclose = function (args) {
setTimeout(initWebSocket, 100);
};
websocket.onerror = function (error) {
websocket.close();
}
}

Просмотреть файл

@ -0,0 +1,76 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Worker
{
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
// sends the location of the visual object, until cancelled
internal class DataSender
{
private const string SendAddressEnvVar = "BOX_ADDRESS";
private static readonly String SendAddress;
private static readonly HttpClient Client;
private static bool ReportError = true;
static DataSender()
{
if (Environment.GetEnvironmentVariable(SendAddressEnvVar) != null)
{
SendAddress = Environment.GetEnvironmentVariable(SendAddressEnvVar);
}
else
{
SendAddress = "web:80";
}
Client = new HttpClient();
}
public static async Task<bool> SendData(string objectId, string content, CancellationToken cancellationToken)
{
try
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Post,
Content = new StringContent(content, Encoding.UTF8),
RequestUri = new Uri($"http://{SendAddress}/api/values?id={objectId}"),
};
request.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain; charset=utf-8");
var response = await Client.SendAsync(request, cancellationToken);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
if (ReportError)
{
Console.WriteLine("Error in sending the data " + response);
ReportError = false;
}
}
else
{
ReportError = true;
return true;
}
}
catch (Exception e)
{
if (ReportError)
{
Console.WriteLine("Error in sending the data " + e.Message);
ReportError = false;
}
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
FROM microsoft/dotnet:2.0-runtime AS base
WORKDIR /app
FROM microsoft/dotnet:2.0-sdk AS build
WORKDIR /src
COPY worker/worker.csproj worker/
RUN dotnet restore worker/worker.csproj
COPY . .
WORKDIR /src/worker
RUN dotnet build worker.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish worker.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENV OBJECT_ENABLE_ROTATION=false
ENTRYPOINT ["dotnet", "worker.dll"]

Просмотреть файл

@ -0,0 +1,143 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Worker
{
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using VisualObjects.Common;
internal class FileStateStore : IStateStore
{
private const string StateFolderName = "Data";
private const string SubFolderNameEnvVar = "Fabric_Id";
private const string StateFileName = "visualobjects.data.xml";
private DataContractSerializer serializer;
private string stateFilePath;
private string stateFolderPath;
public FileStateStore()
: this(GetDefaultFolderPath())
{
}
public FileStateStore(string folderPath)
{
this.stateFolderPath = folderPath;
this.stateFilePath = Path.Combine(folderPath, StateFileName);
this.serializer = new DataContractSerializer(
typeof(VisualObject),
new DataContractSerializerSettings()
{
MaxItemsInObjectGraph = int.MaxValue
});
}
public async Task<VisualObject> ReadAsync(CancellationToken cancellationToken)
{
if (!File.Exists(this.stateFilePath))
{
Console.WriteLine($"State file {this.stateFilePath} does not exist. Creating new object.");
return VisualObject.CreateRandom(Guid.NewGuid().ToString());
}
// file exists read it
byte[] data = null;
using (var stream = new FileStream(
this.stateFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.None,
4096,
true))
{
data = new byte[stream.Length];
await stream.ReadAsync(data, 0, data.Length, cancellationToken);
}
// deserialize
try
{
return this.Deserialize(data);
}
catch (Exception e)
{
Console.WriteLine($"Read error. recreating the object. {e.ToString()}");
return VisualObject.CreateRandom(Guid.NewGuid().ToString());
}
}
public async Task WriteAsync(VisualObject state, CancellationToken cancellationToken)
{
if (!Directory.Exists(this.stateFolderPath))
{
Directory.CreateDirectory(this.stateFolderPath);
}
var data = this.Serialize(state);
using (var stream = new FileStream(
this.stateFilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None,
4096,
true))
{
await stream.WriteAsync(data, 0, data.Length, cancellationToken);
}
}
private byte[] Serialize(VisualObject parameters)
{
using (var stream = new MemoryStream())
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(stream))
{
this.serializer.WriteObject(writer, parameters);
writer.Flush();
return stream.ToArray();
}
}
}
private VisualObject Deserialize(byte[] parameters)
{
if (parameters == null)
{
throw new ArgumentNullException("parameters", "argument should not be null");
}
using (var stream = new MemoryStream(parameters))
{
using (var reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max))
{
return (VisualObject)this.serializer.ReadObject(reader);
}
}
}
private static string GetDefaultFolderPath()
{
var subFolderName = Environment.GetEnvironmentVariable(SubFolderNameEnvVar);
if (null == subFolderName)
{
subFolderName = String.Empty;
}
var codeFolderFullPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var baseFolderFullPath = Path.GetDirectoryName(codeFolderFullPath);
var stateFolderPath = Path.Combine(baseFolderFullPath, StateFolderName, subFolderName);
return stateFolderPath;
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Worker
{
using System.Threading;
using System.Threading.Tasks;
using VisualObjects.Common;
internal interface IStateStore
{
Task<VisualObject> ReadAsync(CancellationToken cancellationToken);
Task WriteAsync(VisualObject obj, CancellationToken cancellationToken);
}
}

Просмотреть файл

@ -0,0 +1,108 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Worker
{
using System;
using System.Threading;
using System.Threading.Tasks;
using VisualObjects.Common;
// moves a visual object and save it to the store
internal class Mover
{
private const string MoveSpeedEnvVar = "OBJECT_MOVE_INTERVAL_MILLIS";
private const string EnableRotationEnv = "OBJECT_ENABLE_ROTATION";
private static readonly TimeSpan MoveSpeed;
private static readonly bool Rotate;
static Mover()
{
if (bool.TryParse(
Environment.GetEnvironmentVariable(EnableRotationEnv),
out bool rotate))
{
Rotate = rotate;
}
else
{
Rotate = false;
}
if (long.TryParse(
Environment.GetEnvironmentVariable(MoveSpeedEnvVar),
out long millis))
{
MoveSpeed = TimeSpan.FromMilliseconds(millis);
}
else
{
MoveSpeed = TimeSpan.FromMilliseconds(50);
}
}
public static async Task MoveAsync(
IStateStore stateStore,
CancellationToken cancellationToken)
{
long totalMoves = 0;
long successfulMoves = 0;
while (!cancellationToken.IsCancellationRequested)
{
totalMoves++;
var obj = await ReadObjectAsync(stateStore, cancellationToken);
if (obj != null)
{
if (await DataSender.SendData(obj.Name, obj.ToJson(), cancellationToken))
{
obj.Move(Rotate);
await WriteObjectAsync(stateStore, obj, cancellationToken);
successfulMoves++;
}
}
if ((totalMoves % 1000) == 0)
{
Console.WriteLine($"Completed {successfulMoves}/{totalMoves} sucessful moves.");
}
await Task.Delay(MoveSpeed);
}
}
public static async Task<VisualObject> ReadObjectAsync(
IStateStore stateStore,
CancellationToken cancellationToken)
{
try
{
return await stateStore.ReadAsync(cancellationToken);
}
catch (Exception e)
{
Console.WriteLine($"Error in reading the object. {e.ToString()}");
return null;
}
}
public static async Task WriteObjectAsync(
IStateStore stateStore,
VisualObject obj,
CancellationToken cancellationToken)
{
try
{
await stateStore.WriteAsync(obj, cancellationToken);
}
catch (Exception e)
{
Console.WriteLine($"Error in writing the object. {e.ToString()}");
}
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------
namespace VisualObjects.Worker
{
using System.Threading;
class Program
{
static void Main(string[] args)
{
Mover.MoveAsync(new FileStateStore(), CancellationToken.None).Wait();
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
## Service definition ##
application:
schemaVersion: 0.0.1
name: VisualObjects
services:
- name: worker
description: worker description.
osType: Windows
codePackages:
- name: worker
image: worker:dev
endpoints:
- name: workerListener
port: 20009
resources:
requests:
cpu: 0.5
memoryInGB: 1
replicaCount: 1
networkRefs:
- name: VisualObjectsNetwork

Просмотреть файл

@ -0,0 +1,19 @@
FROM microsoft/dotnet:2.0-runtime AS base
WORKDIR /app
FROM microsoft/dotnet:2.0-sdk AS build
WORKDIR /src
COPY worker/worker.csproj worker/
RUN dotnet restore worker/worker.csproj
COPY . .
WORKDIR /src/worker
RUN dotnet build worker.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish worker.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENV OBJECT_ENABLE_ROTATION=true
ENTRYPOINT ["dotnet", "worker.dll"]

Просмотреть файл

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.SFApp.Targets" Version="0.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VisualObjects.Common\VisualObjects.Common.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,110 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "westus",
"metadata": {
"description": "Location of the resources."
}
}
},
"resources": [
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsNetworkWindows",
"type": "Microsoft.ServiceFabric/networks",
"location": "[parameters('location')]",
"dependsOn": [],
"properties": {
"schemaVersion": "0.0.1",
"addressPrefix": "10.0.0.4/22",
"ingressConfig": {
"layer4": [
{
"publicPort": "80",
"applicationName": "visualObjectsAppWindows",
"serviceName": "web",
"endpointName": "webListener"
}
]
}
}
},
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsAppWindows",
"type": "Microsoft.ServiceFabric/applications",
"location": "[parameters('location')]",
"dependsOn": [
"Microsoft.ServiceFabric/networks/visualObjectsNetworkWindows"
],
"properties": {
"description": "Service Fabric Mesh Visual Objects Application!",
"services": [
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "web",
"properties": {
"description": "Service Fabric Mesh Visual Objects Web Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-web:1.0-nanoserver-1709",
"endpoints": [
{
"name": "webListener",
"port": "80"
}
],
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "1",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
},
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "worker",
"properties": {
"description": "Service Fabric Mesh Visual Objects Worker Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-worker:1.0-nanoserver-1709",
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "1",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
}
]
}
}
]
}

Просмотреть файл

@ -0,0 +1,110 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "westus",
"metadata": {
"description": "Location of the resources."
}
}
},
"resources": [
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsNetworkWindows",
"type": "Microsoft.ServiceFabric/networks",
"location": "[parameters('location')]",
"dependsOn": [],
"properties": {
"schemaVersion": "0.0.1",
"addressPrefix": "10.0.0.4/22",
"ingressConfig": {
"layer4": [
{
"publicPort": "80",
"applicationName": "visualObjectsAppWindows",
"serviceName": "web",
"endpointName": "webListener"
}
]
}
}
},
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsAppWindows",
"type": "Microsoft.ServiceFabric/applications",
"location": "[parameters('location')]",
"dependsOn": [
"Microsoft.ServiceFabric/networks/visualObjectsNetworkWindows"
],
"properties": {
"description": "Service Fabric Mesh Visual Objects Application!",
"services": [
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "web",
"properties": {
"description": "Service Fabric Mesh Visual Objects Web Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-web:1.0-nanoserver-1709",
"endpoints": [
{
"name": "webListener",
"port": "80"
}
],
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "1",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
},
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "worker",
"properties": {
"description": "Service Fabric Mesh Visual Objects Worker Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-worker:1.0-nanoserver-1709",
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "3",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
}
]
}
}
]
}

Просмотреть файл

@ -0,0 +1,110 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "westus",
"metadata": {
"description": "Location of the resources."
}
}
},
"resources": [
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsNetworkWindows",
"type": "Microsoft.ServiceFabric/networks",
"location": "[parameters('location')]",
"dependsOn": [],
"properties": {
"schemaVersion": "0.0.1",
"addressPrefix": "10.0.0.4/22",
"ingressConfig": {
"layer4": [
{
"publicPort": "80",
"applicationName": "visualObjectsAppWindows",
"serviceName": "web",
"endpointName": "webListener"
}
]
}
}
},
{
"apiVersion": "2018-03-01-privatepreview",
"name": "visualObjectsAppWindows",
"type": "Microsoft.ServiceFabric/applications",
"location": "[parameters('location')]",
"dependsOn": [
"Microsoft.ServiceFabric/networks/visualObjectsNetworkWindows"
],
"properties": {
"description": "Service Fabric Mesh Visual Objects Application!",
"services": [
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "web",
"properties": {
"description": "Service Fabric Mesh Visual Objects Web Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-web:1.0-nanoserver-1709",
"endpoints": [
{
"name": "webListener",
"port": "80"
}
],
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "1",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
},
{
"type": "Microsoft.ServiceFabric/services",
"location": "[parameters('location')]",
"name": "worker",
"properties": {
"description": "Service Fabric Mesh Visual Objects Worker Service.",
"osType": "windows",
"codePackages": [
{
"name": "code",
"image": "seabreeze/azure-mesh-visualobjects-worker:1.0-rotate-nanoserver-1709",
"resources": {
"requests": {
"cpu": "1",
"memoryInGB": "1"
}
}
}
],
"replicaCount": "3",
"networkRefs": [
{
"name": "[resourceId('Microsoft.ServiceFabric/networks', 'visualObjectsNetworkWindows')]"
}
]
}
}
]
}
}
]
}