Created
September 10, 2021 23:00
-
-
Save DelphiWorlds/ed4a938ad49072467c3f882af3ff338c to your computer and use it in GitHub Desktop.
Example of how a Bonjour service *might* be set up on macOS. Has not been fully tested
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit Unit1; | |
// With help from this SO post: | |
// https://stackoverflow.com/a/16678161/3164070 | |
// ******* NOTE ********* | |
// As per the comment in the Acivate method: | |
// This assumes you have actually created a socket that is listening on the selected port | |
interface | |
uses | |
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, | |
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, | |
Macapi.Foundation, Macapi.ObjectiveC, Macapi.CocoaTypes; | |
type | |
NSRunLoopMode = NSString; | |
PNSInputStream = ^NSInputStream; | |
PNSOutputStream = ^NSOutputStream; | |
NSNetServiceClass = interface(NSObjectClass) | |
['{3E78C456-0906-4BDB-98A3-946ACF2A36B7}'] | |
{class} function dataFromTXTRecordDictionary(txtDictionary: NSDictionary): NSData; cdecl; | |
{class} function dictionaryFromTXTRecordData(txtData: NSData): NSDictionary; cdecl; | |
end; | |
NSNetService = interface(NSObject) | |
['{64E3A9B9-03F2-4E69-8586-FF6AAB14E94E}'] | |
function &type: NSString; cdecl; | |
function addresses: NSArray; cdecl; | |
function delegate: Pointer; cdecl; | |
function domain: NSString; cdecl; | |
function getInputStream(inputStream: PNSInputStream; outputStream: PNSOutputStream): Boolean; cdecl; | |
function hostName: NSString; cdecl; | |
function includesPeerToPeer: Boolean; cdecl; | |
function initWithDomain(domain: NSString; &type: NSString; name: NSString): Pointer; overload; cdecl; | |
function initWithDomain(domain: NSString; &type: NSString; name: NSString; port: Integer): Pointer; overload; cdecl; | |
function name: NSString; cdecl; | |
function port: NSInteger; cdecl; | |
procedure publish; cdecl; | |
procedure publishWithOptions(options: NSNetServiceOptions); cdecl; | |
procedure removeFromRunLoop(aRunLoop: NSRunLoop; forMode: NSRunLoopMode); cdecl; | |
procedure resolveWithTimeout(timeout: NSTimeInterval); cdecl; | |
procedure scheduleInRunLoop(aRunLoop: NSRunLoop; forMode: NSRunLoopMode); cdecl; | |
procedure setDelegate(delegate: Pointer); cdecl; | |
procedure setIncludesPeerToPeer(includesPeerToPeer: Boolean); cdecl; | |
function setTXTRecordData(recordData: NSData): Boolean; cdecl; | |
procedure startMonitoring; cdecl; | |
procedure stop; cdecl; | |
procedure stopMonitoring; cdecl; | |
function TXTRecordData: NSData; cdecl; | |
end; | |
TNSNetService = class(TOCGenericImport<NSNetServiceClass, NSNetService>) end; | |
NSNetServiceDelegate = interface(IObjectiveC) | |
['{00728682-DC04-47C4-9497-43D2BBA88F2F}'] | |
procedure netServiceDidAcceptConnectionWithInputStream(sender: NSNetService; didAcceptConnectionWithInputStream: NSInputStream; | |
outputStream: NSOutputStream); cdecl; | |
procedure netServiceDidNotPublish(sender: NSNetService; didNotPublish: NSDictionary); cdecl; | |
procedure netServiceDidNotResolve(sender: NSNetService; didNotResolve: NSDictionary); cdecl; | |
procedure netServiceDidPublish(sender: NSNetService); cdecl; | |
procedure netServiceDidResolveAddress(sender: NSNetService); cdecl; | |
procedure netServiceDidStop(sender: NSNetService); cdecl; | |
procedure netServiceDidUpdateTXTRecordData(sender: NSNetService; didUpdateTXTRecordData: NSData); cdecl; | |
procedure netServiceWillPublish(sender: NSNetService); cdecl; | |
procedure netServiceWillResolve(sender: NSNetService); cdecl; | |
end; | |
TBonjour = class; | |
TNSNetServiceDelegate = class(TOCLocal, NSNetServiceDelegate) | |
private | |
FBonjour: TBonjour; | |
public | |
{ NSNetServiceDelegate } | |
procedure netServiceDidAcceptConnectionWithInputStream(sender: NSNetService; didAcceptConnectionWithInputStream: NSInputStream; | |
outputStream: NSOutputStream); cdecl; | |
procedure netServiceDidNotPublish(sender: NSNetService; didNotPublish: NSDictionary); cdecl; | |
procedure netServiceDidNotResolve(sender: NSNetService; didNotResolve: NSDictionary); cdecl; | |
procedure netServiceDidPublish(sender: NSNetService); cdecl; | |
procedure netServiceDidResolveAddress(sender: NSNetService); cdecl; | |
procedure netServiceDidStop(sender: NSNetService); cdecl; | |
procedure netServiceDidUpdateTXTRecordData(sender: NSNetService; didUpdateTXTRecordData: NSData); cdecl; | |
procedure netServiceWillPublish(sender: NSNetService); cdecl; | |
procedure netServiceWillResolve(sender: NSNetService); cdecl; | |
public | |
constructor Create(const ABonjour: TBonjour); | |
end; | |
TBonjour = class(TObject) | |
private | |
FPort: Integer; | |
FService: NSNetService; | |
FServiceDelegate: TNSNetServiceDelegate; | |
FServiceName: string; | |
public | |
constructor Create(const AServiceName: string); | |
destructor Destroy; override; | |
procedure Activate; | |
property Port: Integer read FPort write FPort; | |
end; | |
TForm1 = class(TForm) | |
Button1: TButton; | |
procedure Button1Click(Sender: TObject); | |
private | |
FBonjour: TBonjour; | |
public | |
constructor Create(AOwner: TComponent); override; | |
destructor Destroy; override; | |
end; | |
var | |
Form1: TForm1; | |
implementation | |
{$R *.fmx} | |
uses | |
Macapi.Helpers; | |
{ TNSNetServiceDelegate } | |
constructor TNSNetServiceDelegate.Create(const ABonjour: TBonjour); | |
begin | |
inherited Create; | |
FBonjour := ABonjour; | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidAcceptConnectionWithInputStream(sender: NSNetService; didAcceptConnectionWithInputStream: NSInputStream; | |
outputStream: NSOutputStream); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidAcceptConnectionWithInputStream'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidNotPublish(sender: NSNetService; didNotPublish: NSDictionary); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidNotPublish'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidNotResolve(sender: NSNetService; didNotResolve: NSDictionary); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidNotResolve'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidPublish(sender: NSNetService); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidPublish'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidResolveAddress(sender: NSNetService); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidResolveAddress'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidStop(sender: NSNetService); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidStop'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceDidUpdateTXTRecordData(sender: NSNetService; didUpdateTXTRecordData: NSData); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceDidUpdateTXTRecordData'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceWillPublish(sender: NSNetService); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceWillPublish'); | |
end; | |
procedure TNSNetServiceDelegate.netServiceWillResolve(sender: NSNetService); | |
begin | |
Log.d('TNSNetServiceDelegate.netServiceWillResolve'); | |
end; | |
{ TBonjour } | |
constructor TBonjour.Create(const AServiceName: string); | |
begin | |
inherited Create; | |
FServiceName := AServiceName; | |
FServiceDelegate := TNSNetServiceDelegate.Create(Self); | |
end; | |
destructor TBonjour.Destroy; | |
begin | |
FServiceDelegate.Free; | |
inherited; | |
end; | |
procedure TBonjour.Activate; | |
begin | |
// This assumes you have actually created a socket that is listening on the selected port | |
FService := nil; | |
FService := TNSNetService.Create; | |
FService := TNSNetService.Wrap(FService.initWithDomain(StrToNSStr('local.'), StrToNSStr('_' + FServiceName + '._tcp.'), StrToNSStr(''), FPort)); | |
FService.setDelegate(FServiceDelegate.GetObjectID); | |
FService.publish; | |
end; | |
{ TForm1 } | |
constructor TForm1.Create(AOwner: TComponent); | |
begin | |
inherited; | |
FBonjour := TBonjour.Create('YourServiceName'); | |
FBonjour.Port := 8080; | |
end; | |
destructor TForm1.Destroy; | |
begin | |
FBonjour.Free; | |
inherited; | |
end; | |
procedure TForm1.Button1Click(Sender: TObject); | |
begin | |
FBonjour.Activate; | |
end; | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Activate needs to change to this for it to work