Networking

We have described the use of Node.js for an echo server in the previous section. For this demonstration of real-time updating we use WebSockets for a minimal chat client-server system. It is set up for use on a local machine and works with the browsers Chrome, Firefox and Opera. It uses much of the code of the supplied WebSocket client and server examples. (We have retained our original 2015 page showing real time updating using socket.io).

Code of Server

This is a slimmed-down project file for the server.

<SMART>
  <Project version="2" subversion="2">
    <Name>WebSocketServer</Name>
    <Options>
      <Compiler />
      <Codegen>
        <Obfuscation>1</Obfuscation>
        <Devirtualize>1</Devirtualize>
        <MainBody>1</MainBody>
        <CodePacking>1</CodePacking>
        <SmartLinking>1</SmartLinking>
        <Verbosity>0</Verbosity>
      </Codegen>
      <ConditionalDefines />
      <Linker>
        <EmbedJavaScript>0</EmbedJavaScript>
      </Linker>
      <Output>
        <OutputFilePath>output\</OutputFilePath>
      </Output>
      <Import />
      <Execute>
        <Server>1</Server>
        <ExecuteType>3</ExecuteType>
        <ExecuteableName>node.exe</ExecuteableName>
        <ExecuteableParams>--no-warnings --stack-size=1200 %output%</ExecuteableParams>
      </Execute>
     </Options>
    <Files>
      <File type="main">
        <Name>WebSocketServer</Name>
        <Source>
          <![CDATA[uses Unit1;

uses SmartNJ.System;

var Server := TMessageServer.Create;
Server.Run;]]>
        </Source>
      </File>
      <File type="unit">
        <Name>Unit1</Name>
        <Source>
          <![CDATA[
unit Unit1;

// Note: Install the "ws" nodejs module in your output folder before running this demo. 
// 1. Change directory to the output folder (compile to create it first)
// 2. Execute the following via shell:  npm install ws

interface

uses
  System.Types, System.Types.Convert, System.Objects, Nodejs.websocket,
  SmartNJ.System, SmartNJ.Network, SmartNJ.Server.Http, SmartNJ.Server.WebSocket;

type
  TMessageServer = class(TObject)
  private
    FServer: TNJWebSocketServer;
    procedure HandleTextMessage(Sender: TObject; Socket: TNJWebSocketSocket; Info: TNJWebsocketMessage);
  public
    procedure Run;
    constructor Create; virtual;
    destructor  Destroy; override;
  end;

implementation

constructor TMessageServer.Create;
begin
  inherited Create;
  FServer := TNJWebSocketServer.Create;
end;

destructor TMessageServer.Destroy;
begin
  if FServer.Active then
    FServer.Active := false;
  FServer.free;
  inherited;
end;

procedure TMessageServer.Run;
begin
  FServer.Port := 1881;
  // Setup an event handler for text messages.
  FServer.OnTextMessage := @HandleTextMessage;  
  FServer.Active := true;
  WriteLn('Server started, listening to port 1881');
end;

procedure TMessageServer.HandleTextMessage(Sender: TObject; Socket: TNJWebSocketSocket; Info: TNJWebsocketMessage);
begin
  writeLnF("Got message: %s", [Info.wiText]);
  // Send the message to all clients.
  for var ClientNum := 0 to FServer.Count - 1 do  
    FServer.Clients[ClientNum].Send(Info.wiText);
end;

end.
]]>
        </Source>
      </File>
    </Files>
    <Target>Node.js</Target>
    <Generator>Node.js Project</Generator>
  </Project>
</SMART>

Code of Client

This is a slimmed-down project file for the client.

<SMART>
  <Project version="2" subversion="2">
    <Name>WebSocketClient</Name>
    <Options>
      <Compiler />
      <Codegen>
        <Obfuscation>1</Obfuscation>        
        <Devirtualize>1</Devirtualize>
        <MainBody>1</MainBody>
        <CodePacking>1</CodePacking>
        <SmartLinking>1</SmartLinking>
        <Verbosity>1</Verbosity>
      </Codegen>
      <ConditionalDefines />
      <Linker>
        <Theme>default.css</Theme>
        <EmbedJavaScript>1</EmbedJavaScript>
      </Linker>
      <Output>
        <HtmlFileName>WebSocketClient.html</HtmlFileName>
        <OutputFilePath>www\</OutputFilePath>
      </Output>
      <Import />
      <Execute />
    </Options>
    <Files>
      <File type="main">
        <Name>WebSocketClient</Name>
        <Source>
          <![CDATA[uses SmartCL.System, Unit1;

  var Application := TApplication.Create;
  Application.RunApp; ]]>
        </Source>
      </File>
      <File type="unit">
        <Name>Unit1</Name>
        <Source>
          <![CDATA[
unit Unit1;

interface

uses
  Pseudo.CreateForms, // auto-generated unit that creates forms during startup
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms, 
  SmartCL.Application, Form1;

type
  TApplication  = class(TW3CustomApplication)
  end;

implementation

end.]]>
        </Source>
      </File>
      <File type="form">
        <Name>Form1</Name>
        <Source>
          <![CDATA[unit Form1;

interface

uses 
  System.Types, System.Types.Convert,  System.Objects,  System.Time, SmartCL.System,
  SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils,  SmartCL.Forms,  SmartCL.Fonts,
  SmartCL.Theme, SmartCL.Borders,  SmartCL.Net.websocket, SmartCL.Application, 
  SmartCL.Controls.EditBox, SmartCL.Controls.Button, SmartCL.Controls.Memo;

type
  TForm1 = class(TW3Form)
    procedure W3Button1Click(Sender: TObject);
  private
    {$I 'Form1:intf'}
    FSocket: TW3WebSocket;
  protected
    procedure InitializeObject; override;
  end;

implementation

procedure TForm1.W3Button1Click(Sender: TObject);
begin
  FSocket.Connect('ws://127.0.0.1:1881');
end;

procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
  FSocket := TW3WebSocket.Create;
  FSocket.OnOpen := procedure (sender: TW3WebSocket)
  begin    
    FSocket.Write(edtMsg.text);
  end;

  FSocket.OnMessage := procedure (Sender: TW3WebSocket; Message: TWebSocketMessageData)
  begin
    if Message.mdType = wsText then
      TextLog.Add(Message.mdText, true);
  end;
end; 
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.
]]>
        </Source>
        <Design>
          <![CDATA[<?xml version="1.0" encoding="utf-16"?>
<Form version="2" subversion="2">
  <object type="TW3Form">
    <Caption>W3Form</Caption>
    <Name>Form1</Name>
    <object type="TW3Button">
      <Caption>Send</Caption>
      <Width>304</Width>
      <Top>400</Top>
      <Left>8</Left>
      <Height>56</Height>
      <Name>W3Button1</Name>
      <OnClick>W3Button1Click</OnClick>
    </object>
    <object type="TW3EditBox">
      <Text>Hello</Text>
      <Width>400</Width>
      <Top>300</Top>
      <Left>8</Left>
      <Height>32</Height>
      <Name>edtMsg</Name>
    </object>
    <object type="TW3Memo">
      <Width>280</Width>
      <Top>32</Top>
      <Left>8</Left>
      <Height>200</Height>
      <Name>TextLog</Name>
    </object>
  </object>
</Form>]]>
        </Design>
        <AutoCreate>
          <IsAutoCreate>1</IsAutoCreate>
          <IsMainForm>1</IsMainForm>
          <Order>1</Order>
        </AutoCreate>
      </File>
    </Files>
    <Target>Browser</Target>
    <Generator>Visual Components Project</Generator>
  </Project>
</SMART>

Programming - a skill for life!

Developing graphical web pages including 3D, input from keyboard and mouse and storing and loading data