Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


DavidRM last won the day on June 16

DavidRM had the most liked content!

About DavidRM

  • Rank

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location
    Tulsa, OK

Smart Mobile Studio

  • Edition

Recent Profile Visitors

280 profile views
  1. DavidRM

    Page Loading Issues with iPhone Browser

    That seems to have fixed it. Thanks! -David
  2. DavidRM

    Page Loading Issues with iPhone Browser

    I will try that. Thanks! -David
  3. DavidRM

    Page Loading Issues with iPhone Browser

    Those details I mentioned: I have to go into settings, general, iPhone storage, scroll down to safari, select website data. Then swipe left on [the domain name] and press delete Thoughts? -David
  4. I've had some players report that their iPhone browser has a problem loading my Paintball Net UI web page (which was built with SMS). That is, they have to do some kind of "delete data" for the URL, then the page will load again. I'll provide more details from one of the users when I get it. Any ideas? Thanks. -David
  5. DavidRM

    Promises revisited

    I've had to use promises extensively, especially for accessing MySql. I've used Warley Alex's posted promise unit instead of the RTL unit.
  6. DavidRM

    Node.JS Game Loop

    Here is my Smart Mobile Studio adaptation of the Node.JS "node-gameloop" module. My primary modification was some code to make the *next* interval line up with the desired number of ms per tick. I also tightened the window for choosing SetTimeout vs SetImmediate. I needed this to provide the beating heart of Paintball Net's simulation engine. Which, sure, only beats 10 times per second, but I wanted it to be as accurate as possible. 🙂 -David unit UPBNGameGameLoop; interface uses System.Types, System.Types.Convert, System.Time, System.Streams, System.Reader, System.Writer, System.Device.Storage, SmartNJ.System, SmartNJ.Streams, SmartNJ.Device.Storage, SmartNJ.Application, NodeJS.Core; var GameLoopActive: boolean; type TGameLoopCallback = procedure(delta: float); procedure StartGameLoop(update: TGameLoopCallback; msInterval: integer); procedure StopGameLoop; implementation procedure SetImmediate(const Entrypoint: TProcedureRef); external 'setImmediate'; const Seconds2Nano = 1e9; Nano2Seconds = 1 / Seconds2Nano; MS2Nano = 1e6; Nano2MS = 1 / MS2Nano; var _loopProc: TGameLoopCallback; _loopLengthHR: float; _loopPrevHR, _loopTargetHR: float; function GetHRTime: float; var hrTime: Variant; begin // I need a more up-to-date node to use the bigint() function. // asm // @Result = process.hrtime.bigint(); // end; asm @hrTime = process.hrtime(); end; Result := (hrTime[0] * Seconds2Nano) + hrtime[1]; end; procedure DoGameLoop; var now, delta: float; remaining: integer; begin if GameLoopActive then begin now := GetHRTime; if now >= _loopTargetHR then begin delta := now - _loopPrevHR; _loopPrevHR := now; _loopTargetHR := now + _loopLengthHR; if delta > _loopLengthHR then begin _loopTargetHR -= (delta - _loopLengthHR); end; _loopProc(delta * Nano2Seconds); end; if GameLoopActive then begin remaining := Trunc((_loopTargetHR - GetHRTime) * Nano2MS); if remaining >= 4 {16} then SetTimeout(DoGameLoop, remaining) else SetImmediate(DoGameLoop); end; end; end; procedure StartGameLoop(update: TGameLoopCallback; msInterval: integer); begin if not GameLoopActive then begin GameLoopActive := True; _loopLengthHR := msInterval * MS2Nano; _loopProc := update; _loopPrevHR := GetHRTime; _loopTargetHR := _loopPrevHR; SetImmediate(DoGameLoop); end; end; procedure StopGameLoop; begin GameLoopActive := False; _loopProc := nil; end; end.
  7. DavidRM

    How do I use Secure Websockets (WSS)?

    Alrighty then. I have a plan of attack now. THanks! -David
  8. DavidRM

    How do I use Secure Websockets (WSS)?

    Some of my users have connected with mobile devices. I've done it with a Google Pixel 2, though not for long stretches of time. I haven't heard of any dropping connections like that. IPhones and Android both.
  9. DavidRM

    How do I use Secure Websockets (WSS)?

    @lynkfs It sounds like I should get the Websocket upgraded to SSL before messing with the web page. But since the backend doesn't have a domain name, I'm not sure how the certificate would work. This part is all quite new to me. (Hell, before last fall NodeJS/Websocket was totally new to me). I'm kinda figuring out as I go.
  10. What I'm trying to do: Keep the web page for the app separate from the backend server for the app. Right now, I have the web page serving the client, which opens a Websocket (ws) to the backend server. I want to add HTTPS to the web page and I want to support secure Websockets to the backend. The first part seems pretty straightforward. I'll just get an SSL certificate for the web page. But... How does that affect the second part? Can I still open a non-secure WS connection from the client? Or will the browser balk? Also, what do I need to do to the backend server to get it to handle secure WS connections? Thanks! -David
  11. DavidRM

    Server Side file creation and writing to files

    Fine. Answer your own question. I actually *knew* this one... 😉
  12. DavidRM

    Request for feedback: Changing class names in the RTL

    This. ^^^^^ That said, I vote for the change. -David
  13. DavidRM

    UI layout

    Now add some TW3Labels to your layout demo and experience Real Pain. 😉
  14. DavidRM

    Node.JS WebSocket Client Socket

    This is me sharing again. The NodeJS WebSocket server socket is implemented in SMS. But I didn't find an implementation of the WebSocket client socket. Sometimes an SMS NodeJS server needs to connect to another server. So I kinda hacked this together using the server socket as a guide. unit UPBNCommonNJWebSocket; interface uses System.Types, System.Types.Convert, System.Time, System.Streams, System.Reader, System.Writer, System.Device.Storage, System.Objects, SmartNJ.System, SmartNJ.Streams, SmartNJ.Device.Storage, SmartNJ.Application, NodeJS.Core, NodeJS.WebSocket, SmartNJ.Server.WebSocket; type // Forward declarations TNJWebSocket = class; TNJWebSocketOpenEvent = procedure (Sender: TNJWebSocket); TNJWebSocketCloseEvent = procedure (Sender: TNJWebSocket; Code: integer; const Reason: string); TNJWebSocketErrorEvent = procedure (Sender: TNJWebSocket; Error: TJSErrorObject); TNJWebSocketMessageEvent = procedure (Sender: TNJWebSocket; Message: TNJWebsocketMessage); TNJWebSocket = class(TW3ErrorObject) private FSocket: JWsSocket; public property WSSocket: JWsSocket read FSocket; function SocketState: JWsReadyState; function Connected: boolean; function URL: string; function Protocol: string; procedure Connect(URL: string; Protocols: array of string); overload; procedure Connect(URL: string); overload; procedure Disconnect; overload; procedure Send(const Data: variant); overload; procedure Send(const Text: string); overload; procedure Send(const Data: TStream); overload; property TagData: variant; constructor Create; override; destructor Destroy; override; procedure Ping; published property OnOpen: TNJWebSocketOpenEvent; property OnClosed: TNJWebSocketCloseEvent; property OnMessage: TNJWebSocketMessageEvent; property OnError: TNJWebSocketErrorEvent; end; implementation constructor TNJWebSocket.Create; begin inherited Create; // We dont want to throw exceptions whenever SetLastError() is called ErrorOptions.ThrowExceptions := false; end; destructor TNJWebSocket.Destroy; begin FSocket := nil; inherited; end; procedure TNJWebSocket.Ping; begin if FSocket <> nil then asm (@FSocket).ping(function() {}); end; end; function TNJWebSocket.Protocol: string; begin if FSocket <> nil then Result := FSocket.protocol; end; function TNJWebSocket.URL:String; begin if FSocket <> nil then Result:=FSocket.url; end; function TNJWebSocket.SocketState: JWsReadyState; begin if FSocket <> nil then Result := JWsReadyState( integer( FSocket.readyState) ) else Result := rsClosed; end; function TNJWebSocket.Connected: boolean; begin Result := SocketState = rsOpen; end; procedure TNJWebSocket.Connect(URL: string); begin Connect(Url, []); end; procedure TNJWebSocket.Connect(URL: string; Protocols: Array of string); begin ClearLastError(); (* disconnect socket if already connected *) if connected then disconnect(); (* Allocate new socket *) var WebSocket = WebSocketAPI; asm (@self.FSocket) = new (@WebSocket)(@URL, @Protocols); end; // initialize standard socket events FSocket.on("open", procedure begin if assigned(OnOpen) then OnOpen(self); end); FSocket.on("error", procedure (error: variant) begin SetLastError("internal websocket error"); if assigned(OnError) then OnError(self, TJSErrorObject(error)); end); FSocket.on("message", procedure (message: variant) var ResData: TNJWebsocketMessage; begin if message.IsUint8Array then begin ResData.wiType := mtBinary; ResData.wiBuffer := JBuffer(message); end else begin ResData.wiType := mtText; ResData.wiText := message; end; if assigned(OnMessage) then OnMessage(self, ResData); end); Variant(FSocket).on("close", procedure (code: integer; reason: string) begin if assigned(OnClosed) then OnClosed(self, code, reason); end); end; procedure TNJWebSocket.Disconnect; begin ClearLastError(); if Connected then begin try FSocket.close(); finally FSocket := nil; end; end; end; procedure TNJWebSocket.Send(const Data: variant); begin FSocket.send(data); end; procedure TNJWebSocket.Send(const Text: string); begin FSocket.send(Text); end; procedure TNJWebSocket.Send(const Data: TStream); begin if Data <> nil then begin if Data.position < Data.Size then begin // Get bytes from stream var Bytes := Data.Read(Data.Size - Data.Position); // Convert to typed-array var TypedArray := TDataType.BytesToTypedArray(bytes); // Send as binary FSocket.Send(TypedArray); end; end; end; end. It might be a bit simplified, and it doesn't really follow the SMS component name convention, but it does what I need. And I figured I would share. -David
  15. DavidRM

    RTL Search

    I would find a built-in search of the RTL quite handy. Sorta like the "Find in Files...", where it brings up a list of hits, but searching the current SMS RTL folders and files instead. Could even just be a checkbox option in "Find in Files..." This would be a step in the direction of "better documentation". 😃 Or, at least, easier to review what's already available. Currently, I do this using Notepad++, but that doesn't let me open the results in the SMS IDE. Being in the IDE would provide access to "Find Declaration" and similar features. -David