【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

需要描述

1)实现黑客帝国文字流效果图,JS功能

2)部署在云中,让大家都可以访问,App Service实现

3)大家都能发送消息,并显示在文字流中,PubSub(websocket)实现

 

终极效果显示:

【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

 

执行步骤

1)在 Azure 中创建 App Service 服务,参考官方文档:快速入门:部署 ASP.NET Web 应用

Azure门户中创建App Service的动画演示:

【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

 

2)在 Azure 中创建 PubSub 服务,参考官方文档:快速入门:从 Azure 门户创建 Web PubSub 实例

Azure门户中创建Web PubSub的动画演示:

 【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

 

3)使用Visual Studio 2022创建一个.NET 6.0 Web项目,参考PubSub的文档来创建一个服务端来托管 /negotiate API和Web 页面,参考示例:教程:使用子协议在 WebSocket 客户端之间发布和订阅消息

Program.cs文件内容为:

  • string ConnectionString = "<Web PubSub Access Key>" 获取的办法见第二步创建的PubSub服务的Key页面 --> Connection String

using Azure.Messaging.WebPubSub; using Microsoft.Extensions.Azure;  string ConnectionString = "<Web PubSub Access Key>";  // Add WebPubSub Service  var builder = WebApplication.CreateBuilder(args); builder.Services.AddAzureClients(builder => {     builder.AddWebPubSubServiceClient(ConnectionString, "stream"); });  var app = builder.Build();  app.UseStaticFiles();  app.UseRouting();  //实现生产客户端WebSocket SAS URL app.UseEndpoints(endpoints => {     endpoints.MapGet("/negotiate/{userid}", async (string userid, HttpContext context) =>     {         var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>();         var response = new         {             url = service.GetClientAccessUri(userId: userid, roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri         };         await context.Response.WriteAsJsonAsync(response);     }); });  app.MapGet("/", () => "/index.html");  app.Run();

前端 wwwroot/stream.html 内容为:

<html> <style>     html,     body {         margin: 0;         padding: 0;         background-color: rgb(0, 0, 0);     }      #divList {         width: 98%;         height: 79%;         border: solid 1px rgb(0, 15, 0);         ;         margin: 0px auto;         overflow: hidden;         position: relative;     }      .divText {         position: absolute;     }      .divText span {         display: block;         font-weight: bold;         font-family: Courier New;     } </style> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>  <body> <br>     <h2 style="text-align:center; color:white;">STREAM BOARDCAST (<span id="spanCount">0</span>)</h2>     <div id="divList">     </div>     <h3 style="text-align:left; color:grey;">Send</h3>     <div style=" margin: 5px 15px;">         <input id="inputmessage" style="text-align:left; color:green; width: 86%; height: 55px; font-size: 40px;" onsubmit="sendmessage()"><button             style="text-align:center; color:green; width: 12%; height: 55px;font-size: 40px;" onclick="sendmessage()">Send</button>     </div>     <div style="display:none;">         <h1>Message</h1>         <div id="output"></div>         <br>         <h1>Message</h1>         <div id="outputmsg"></div>     </div>     <script>         var textarray = ["Hello Mooncake,Welcome to use PubSub", "Who are you? Put your PIN ... "];         var wsurl = "";         var wsclient;         let ackId = 0;         (async function () {             let res = await fetch('/negotiate/client_2')             let data = await res.json();             wsurl = data.url;             let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');             ws.onopen = () => {                 console.log('connected');             };              let output = document.querySelector('#output');             let outputmsg = document.querySelector('#outputmsg');              ws.onmessage = event => {                 let d = document.createElement('p');                 d.innerText = event.data;                 output.appendChild(d);                  let message = JSON.parse(event.data);                 if (message.type === 'message' && message.group === 'stream') {                     let d = document.createElement('span');                     d.innerText = message.data;                     textarray.push(message.data);                     outputmsg.appendChild(d);                     window.scrollTo(0, document.body.scrollHeight);                 }             };              ws.onopen = () => {                 console.log('connected');                 ws.send(JSON.stringify({                     type: 'joinGroup',                     group: 'stream',                     ackId: ++ackId                 }));                  wsclient = ws;             };         })();           function sendmessage() {              if (wsclient.readyStatue == WebSocket.OPEN) {                 wsclient.send(JSON.stringify(                     {                         type: "sendToGroup",                         group: "stream",                         data: $('#inputmessage').val(),                         ackId: ++ackId // ackId is optional, use ackId to make sure this action is executed                     }                 ));             }             else {                  wsclient = new WebSocket(wsurl, 'json.webpubsub.azure.v1');                  wsclient.onopen = () => {                     console.log('connected again');                     wsclient.send(JSON.stringify({                         type: "sendToGroup",                         group: "stream",                         data: $('#inputmessage').val(),                         ackId: ++ackId                     }));                   };             }             $('#inputmessage').focus();         }            function rand(min, max) {             return min + Math.round(Math.random() * (max - min));         }          function add(message) {             var maxwdth = $('#divList').width();             var x = rand(0, maxwdth);             var html = '<div class="divText" style="left:' + x + 'px; bottom:500px;">';              var color = [];             for (var i = 1; i < message.length; i++) {                 var f = i.toString(16);                 color.push('0' + f + '0');             }              var fontSize = rand(20, 36);             for (var i = 1; i <= message.length; i++) {                 var c = message[i - 1];                 html += '<span class="s' + i + '" style="color:#' + color[i - 1] + '; font-size:' + fontSize + 'px; text-shadow:0px 0px 10px #' + color[i - 1] + ';">' + c + '</span>';             }             html += '</div>';             $('#divList').append(html);         }          function run() {             var x = rand(0, 100);             if (x < 100) {                 var lgh = textarray.length;                 if (textarray.length > x) add(textarray[x]);                 else                     add(textarray[x % lgh]);             }             $('#spanCount').html($('.divText').size());              $('.divText').each(function () {                 var y = $(this).css('bottom');                 y = parseInt(y);                 y -= $(this).find('span').eq(0).height();                 $(this).css('bottom', '' + y + 'px');                 if (y + $(this).height() <= 0) {                     $(this).remove();                     return;                 }             });              window.setTimeout(run, 200);         }         run();      </script> </body>  </html>

项目结构示意图:

【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

 

项目创建完成后,可以在本机进行调试。正常运行后即可发布到Azure App Service上。因代码简单并且可读性强,可自行理解。

 

4)通过VS 2022发布到App Service中

VS 2022 通过Publish Profile 发布站点演示动画:

【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

发布版本操作完成。

 

附录一:本地黑客帝国文字流效果,可自行输入即修改内容版

复制内容,直接保存在本地文件中,文件命名为 localstream.html后使用浏览器打开即可

<html> <style>     html,     body {         margin: 0;         padding: 0;         background-color: rgb(0, 0, 0);     }      #divList {         width: 98%;         height: 79%;         border: solid 1px rgb(0, 15, 0);         ;         margin: 0px auto;         overflow: hidden;         position: relative;     }      .divText {         position: absolute;     }      .divText span {         display: block;         font-weight: bold;         font-family: Courier New;     } </style> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>  <body> <br>     <h2 style="text-align:center; color:white;">STREAM BOARDCAST (<span id="spanCount">0</span>)</h2>     <div id="divList">     </div>     <h3 style="text-align:left; color:grey;">Send</h3>     <div style=" margin: 5px 15px;">         <input id="inputmessage" style="text-align:left; color:green; width: 86%; height: 55px; font-size: 40px;" onsubmit="sendmessage()"><button             style="text-align:center; color:green; width: 12%; height: 55px;font-size: 40px;" onclick="sendmessage()">Send</button>     </div>     <div style="display:none;">         <h1>Message</h1>         <div id="output"></div>         <br>         <h1>Message</h1>         <div id="outputmsg"></div>     </div>     <script>         var textarray = ["Hello Mooncake,Welcome to use PubSub", "Who are you? Put your PIN ... "];          function sendmessage() {             textarray.push($('#inputmessage').val());             $('#inputmessage').focus();         }            function rand(min, max) {             return min + Math.round(Math.random() * (max - min));         }          function add(message) {             var maxwdth = $('#divList').width();             var x = rand(0, maxwdth);             var html = '<div class="divText" style="left:' + x + 'px; bottom:500px;">';              var color = [];             for (var i = 1; i < message.length; i++) {                 var f = i.toString(16);                 color.push('0' + f + '0');             }              var fontSize = rand(20, 36);             for (var i = 1; i <= message.length; i++) {                 var c = message[i - 1];                 html += '<span class="s' + i + '" style="color:#' + color[i - 1] + '; font-size:' + fontSize + 'px; text-shadow:0px 0px 10px #' + color[i - 1] + ';">' + c + '</span>';             }             html += '</div>';             $('#divList').append(html);         }          function run() {             var x = rand(0, 100);             if (x < 100) {                 var lgh = textarray.length;                 if (textarray.length > x) add(textarray[x]);                 else                     add(textarray[x % lgh]);             }             $('#spanCount').html($('.divText').size());              $('.divText').each(function () {                 var y = $(this).css('bottom');                 y = parseInt(y);                 y -= $(this).find('span').eq(0).height();                 $(this).css('bottom', '' + y + 'px');                 if (y + $(this).height() <= 0) {                     $(this).remove();                     return;                 }             });              window.setTimeout(run, 200);         }         run();      </script> </body>  </html>

PS: 与PubSub版本相比,只是移除了WebSocket的相关代码

运行效果

【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

 

 

参考资料

JS 黑客帝国文字下落效果: https://www.cnblogs.com/zjfree/p/3833592.html 

教程:使用子协议在 WebSocket 客户端之间发布和订阅消息:https://docs.microsoft.com/zh-cn/azure/azure-web-pubsub/tutorial-subprotocol?tabs=csharp#using-a-subprotocol

快速入门:部署 ASP.NET Web 应用:https://docs.azure.cn/zh-cn/app-service/quickstart-dotnetcore?tabs=net60&pivots=development-environment-vs

 

发表评论

相关文章