Unable to run vapor as server into an iOS app - ios

I am trying to add a REST API handling function to my existing iOS App. What I am trying to achieve is to make my iOS app work as local server network. I just started to learn about Vapor.
Face a problem when I want to start the server. It throws error
Unknown command -NSDocumentRevisionsDebugMode
Here is my class
import Vapor
import Leaf
class BackendManager {
var app = Application(.development)
init() {
app.http.server.configuration.hostname = "0.0.0.0"
app.http.server.configuration.port = 8080
app.views.use(.leaf)
app.leaf.cache.isEnabled = app.environment.isRelease
app.leaf.configuration.rootDirectory = Bundle.main.bundlePath
app.routes.defaultMaxBodySize = "50MB"
}
func start() {
Task(priority: .background) {
do {
try app.start()
} catch {
fatalError(String(describing: error))
}
}
}
}
And here is how I call it
let server = BackendManager()
server.start()
Here is my configuration
What am I missing here? Thanks ...

After followed the solution suggested in (Xcode and Python) error: unrecognized arguments: -NSDocumentRevisionsDebugMode
It will throw another error -AppleLanguages
Someone in the Discord group helped me to solve this by passing this configuration before start the server
app.environment.arguments = [app.environment.arguments[0]] and it is done
Hope this will help anyone affected in the future

Related

iOS app crashes on iphone device when using httpclient and .net maui

Build environment:
Macbook M1
vscode(1.69.0) as well as vs2022 (17.3)
Steps to reproduce:
create new Maui app
add nuget package "Microsoft.Extensions.Http" Version="6.0.0" to project
Modify MauiProgram.cs:
builder.Services.AddHttpClient<EndPointAHttpClient>(client =>
{
var EndPointA = "https://www.montemagno.com/";
client.BaseAddress = new Uri(EndPointA);
});
public class EndPointAHttpClient
{
public EndPointAHttpClient(HttpClient client)
{
Client = client;
}
public HttpClient Client { get; }
}
Publish:
dotnet publish <project.csproj> -f:net6.0-ios -c:Release /p:ServerAddress=<xxx.xxx.xxx.xxx> /p:ServerUser=user /p:TcpPort=58181 /p:ServerPassword=pwd -p:AotAssemblies=false
Install on iphone using Transporter/TestFlight
CRASHES WHEN OPENING THE APP
Please let me know:
1. Is there any demo code that works
2. Kindly provide advise on how I can use HttpClient in a .net Maui app
Use the code found here. https://github.com/dotnet/maui-samples/tree/main/6.0/WebServices/TodoREST/TodoREST/Services
Grab the RestService, IRestService, HttpsClientHandlerService and IHttpsClientHandlerService.
Get the Contstants file as well.
https://github.com/dotnet/maui-samples/blob/main/6.0/WebServices/TodoREST/TodoREST/Constants.cs
Makes sure you add your Url to the HttpsClientHandlerService like so. I was getting a System.Net.WebException: Error: TrustFailure. The only way I was able to catch what was happening was using Sentry.io. I guessed that this might be the problem.
public bool IsSafeUrl(NSUrlSessionHandler sender, string url, Security.SecTrust trust)
{
if (url.StartsWith("https://localhost") || url.StartsWith("https://yourservice.azurewebsites.net"))
return true;
return false;
}
Then change this line.
var handler = new NSUrlSessionHandler
{
TrustOverrideForUrl = IsSafeUrl
};

Launching Ktor app via Docker causes: No Koin Context configured. Please use startKoin or koinApplication DSL

I'm trying to launch my Ktor backend app in Docker. But I have an exception on app start:
java.lang.IllegalStateException: No Koin Context configured. Please use startKoin or koinApplication DSL.
at org.koin.core.context.KoinContextHandler.getContext(KoinContextHandler.kt:29)
at org.koin.core.context.KoinContextHandler.get(KoinContextHandler.kt:35)
at org.koin.ktor.ext.KtorApplicationExtKt.getKoin(KtorApplicationExt.kt:34)
at com.widgets.ApplicationKt$module$$inlined$inject$1.invoke(KtorApplicationExt.kt:77)
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
at com.widgets.ApplicationKt$module$4.invoke(Application.kt:117)
at com.widgets.ApplicationKt$module$4.invoke(Application.kt)
at io.ktor.auth.Authentication.configure(Authentication.kt:77)
at io.ktor.auth.Authentication$Feature.install(Authentication.kt:165)
at io.ktor.auth.Authentication$Feature.install(Authentication.kt:148)
at io.ktor.application.ApplicationFeatureKt.install(ApplicationFeature.kt:68)
at com.widgets.ApplicationKt.module(Application.kt:116)
at com.widgets.ApplicationKt.module$default(Application.kt:91)
This is my Application code:
fun main(args: Array<String>) {
embeddedServer(Netty) {
module {
install(Koin) {
modules(
module {
single<Logger> { BackendLogger() }
},
ApiInjection.koinBeans
// ...
)
}
apiModule()
}
}.start(wait = true)
}
#kotlin.jvm.JvmOverloads
fun Application.apiModule() {
val userApi by inject<UserApi>() // when this dependency used - I have a crash
// ...
}
When I launch my app locally (Intellij Idea) all works fine. So why Koin installing doesn't work correctly?
After long researching finally I've found solution.
I added this line to build.gradle file:
application {
mainClassName = "com.mypackage.ApplicationKt"
}
And also I edited resources/application.conf file:
application {
modules = [ com.mypackage ]
// modules = [ com.mypackage.ApplicationKt.module ] // previous version
}
So it helps me! And I hope it can help you!

SwiftyZeroMQ Publisher does not recognise subscriber after first message is published

Problem: I fail subscribing to my publisher implemented in swift as soon as the publisher has published its first message.
Goal: Publish a data stream over ZeroMQ from my swift app. Then connect and disconnect a few subscribers and get messages through.
Background: I use swift5 and SwiftyZeroMQ5 (I have tested SwiftyZeroMQ too), I deploy on iPhone. I try to subscribe from both swift and python3. It only works if I connect my subscriber prior to publishing the first message. It also works if I first connect my subscriber then start the publisher app, then publishes. Corresponding publish and subscribe code on python3 does not require launching in any specific order and represents the behaviour I want.
Since I get the sub/pub to work if I start i specific order, I know that IP-numbers, ports and topic, formatting etc are correct.
Note that the behaviour is the same when I subscribe from both python3 and swift - it is not compatibility issues between swift and python.
Error messages: No error messages, the poller simply does not trigger if the processes are not started in the described order. The poller do trigger and messages and received if the processes are started in the described order.
What I tried: I've tried different combinations of publishers and subscribers regarding code base and devices.
Swift pub to swift sub on same device [only works in described order]
Swift pub to swift sub on different devices [only works in described order]
Swift pub to python3 sub [only works in described order]
Python3 pub to swift sub [works independent of start order]
Python3 pub to python3 sub [works independent of start order]
My conclusion: There is a problem in the swift publisher socket: it fails to recognise new subscribers after it has published its first message.
Swift code for publisher, initPublisher is called in viewDidLoad(). ZeroMQ library version is 4.2.2:
import SwiftyZeroMQ5
var context: SwiftyZeroMQ.Context = try! SwiftyZeroMQ.Context()
var gpsPublisher: SwiftyZeroMQ.Socket?
let gpsPublishEndPoint = "tcp://*:5560"
// Init the publisher socket
func initPublisher()->Bool{
do{
self.gpsPublisher = try context.socket(.publish)
try self.gpsPublisher?.setSendBufferSize(4096)
try self.gpsPublisher?.setLinger(0) // Dont buffer messages
try self.gpsPublisher?.bind(self.gpsPublishEndPoint)
return true
}
catch{
print("Publish setup failed!")
return false
}
}
// ZMQ publish. Publishes string and serialized json-object
func publish(socket: SwiftyZeroMQ.Socket?, topic: String, json: JSON)->Bool{
// Create string with topic and json representation
let publishStr = getJsonStringAndTopic(topic: topic, json: json)
do{
try socket?.send(string: publishStr)
print("publish: Published: " + publishStr)
return true
}
catch{
print("publish: Error, tried to publish, but failed: " + publishStr)
return false
}
}
//The function is repeatedly called in a thread. Only function call shown here below.
_ = self.publish(socket: self.gpsPublisher, topic: "myTopic", json: json)
The python3 subscriber code,
zmq.zmq_version() -> '4.3.2':
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, 'myTopic')
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = auxiliaries.zmq.demogrify(msg)
_print((topic, msg))
except zmq.error.Again as error:
_print(str(error))
except KeyboardInterrupt:
auxiliaries.zmq.close_socket_gracefully(socket)
socket = None
Any help, interesting test setups etc is very much appreciated.
I did some more testing and found out a few things and a workaround.
The code works as intended when running on an iPhone simulator (simulator is x86_64 architecture, iPhone8 is armv7)
I don't think it is related, but I did find it interesting. Certain multicast and broadcast protocols require an approval from Apple. You can run without the approval on simulators, but not in devices. Apple networking multicast entitlement. Since it partially works I did rule this out.
The workaround is to bind the socket again prior to each publish. This throws the error "Address already in use", butt seem to not do much harm.
Without unreasonable delays in between publish messages, the pub-sub fails after 500-1000 messages if the publish socket is not binded again when running from the iPhone.
I made a minimal working example app that you can play around with if you want to, or need to dig deeper. It has buttons for "init", "bind", "publish" and "bind and publish". You can send a batch of messages and check timings etc.
I run the app towards a python3 script.
I included SwiftyZeroMQ5 via cocoapods.
Podfile:
platform :ios, '13.0'
target 'ZMQtest' do
use_frameworks!
pod 'SwiftyZeroMQ5'
end
SwiftCode (set up the buttons your self..)
import UIKit
import SwiftyZeroMQ5
class ViewController: UIViewController {
let context = try! SwiftyZeroMQ.Context()
var publisher: SwiftyZeroMQ.Socket?
let publishEndPoint = "tcp://*:5560"
var cnt = 0
let quota = 1200
#IBAction func publishButtonPressed(_ sender: Any) {
while cnt < quota {
publish()
//usleep(10000)
}
cnt = 1
}
#IBAction func bindAndPublishButtonPressed(_ sender: Any) {
while cnt < quota {
bindPublisher()
publish()
}
cnt = 1
}
#IBAction func initPubButtonPressed(_ sender: Any) {
initPublisher()
}
#IBAction func bindPublisherButtonPressed(_ sender: Any) {
bindPublisher()
}
#IBOutlet weak var statusLabel: UILabel!
// **************
// Init publisher
func initPublisher(){
do {
self.publisher = try context.socket(.publish)
print("Publisher socket created")
}
catch {
print("initPublisher error: ", error)
}
}
// **************
// Bind publisher
func bindPublisher(){
do {
try self.publisher?.bind(publishEndPoint)
print("Publisher socket binded to :", publishEndPoint)
}
catch {
print("bindPublisher error: ", error)
}
}
// *****************
// Publish a message
func publish(){
// Publish dummy string
do{
cnt += 1
let str = "topic {\"key\": \"" + String(cnt) + "\"}"
try self.publisher?.send(string: str)
statusLabel.text = str
print("Publish message no: ", String(cnt))
}
catch{
print("publisher error: ", error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
And the python3 code:
#!/usr/bin/env python3
'''Minimal running example of a ZMQ SUB socket.'''
import json
import zmq
def demogrify(msg: str):
'''inverse of mogrify()'''
try:
(topic, message) = msg.split(maxsplit=1)
except ValueError:
(topic, message) = (msg, '{}')
return topic, json.loads(message)
def close_socket_gracefully(socket):
'''graceful termination'''
socket.setsockopt(zmq.LINGER, 0) # to avoid hanging infinitely
socket.close()
if __name__ == "__main__":
context = zmq.Context()
socket = context.socket(zmq.SUB) #pylint: disable=no-member
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, '') #pylint: disable=no-member
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = demogrify(msg)
print((topic, msg))
except zmq.error.Again as error:
print(str(error))
except KeyboardInterrupt:
close_socket_gracefully(socket)
socket = None
Should I mark this issue as solved or not?

How to extract the connection from function with return in swift?

I am trying to connect with my smart lamp by LIFXClient framework, but unfortunately I do not understand how to use this library. The library looks very simple, here is link.
I'm trying changing color by this function:
LIFXClient.connect(host: .ipv4(IPv4Address("192.168.1.4")!)).then { client in
return client.light.setColor(color: .orange)
}
But this creating new connection with different local port every time I use it. Because of lack of free ports after changing colors quickly I can not make a new connection with lamp.
I have been trying a few days not to create a new connection, but to use just one, unfortunately I do not know how to do this.
The function from the LIFXClient to connect to lamp:
public class LIFXClient: LIFXConnection {
public class func connect(host: NWEndpoint.Host, port: NWEndpoint.Port = 56700, queue: DispatchQueue = DispatchQueue(label: "LIFX Queue"), source: UInt32 = UInt32.random(), target: UInt64 = 0) -> Promise<LIFXClient> {
return NWConnection(host: host, port: port, using: .udp).connect(queue: queue).map { connection in
return LIFXClient(connection: connection, source: source, target: target)
}
}
}
If I only could save client.light reference it would be great, but unfortunately I can't do that:
var myClient: LIFXClient
LIFXClient.connect(host: .ipv4(IPv4Address("192.168.1.4")!)).then { client in
myClient = client.light
return client.light.setColor(color: .orange)
}
Developer of this framework does not write back to me, and I really have no ideas how to solve it.
Thank you very much for all your help.

Redirect all DNS requests to custom resolver in iOS app

everyone.
I am trying to override dns resolver settings in my iOS app.
I used NEVPNManager to install a personal vpn and then used onDemandRules to set specific dns servers.
So far my code works for some domains.
Below is my code.
When I put "*.com" in matchDomains, it works perfectly.
But what I want to do is to redirect all dns queries to specific dns server.
I tried empty matchDomains([]) and empty string([""]).
I also tried wildcard expression like ["*"] and ["*.*].
So far I had no success.
It's been a few days and I still can't figure it out.
Can anybody tell me what I am missing here?
Thanks in advance.
let manager = NEVPNManager.sharedManager()
manager.loadFromPreferencesWithCompletionHandler { error in
if let vpnError = error {
print("vpn error in loading preferences : \(vpnError)")
return
}
if manager.protocolConfiguration == nil {
let myIPSec = NEVPNProtocolIPSec()
myIPSec.username = "username"
myIPSec.serverAddress = "server address"
myIPSec.passwordReference = self.getPersistentRef()
myIPSec.authenticationMethod = NEVPNIKEAuthenticationMethod.SharedSecret
myIPSec.sharedSecretReference = self.getPersistentRef()
myIPSec.useExtendedAuthentication = true
manager.protocolConfiguration = myIPSec
manager.localizedDescription = "myDNS"
let evaluationRule = NEEvaluateConnectionRule(matchDomains: ["*.com"], andAction: NEEvaluateConnectionRuleAction.ConnectIfNeeded)
evaluationRule.useDNSServers = ["XXX.XXX.XXX.XXX"]
let onDemandRule = NEOnDemandRuleEvaluateConnection()
onDemandRule.connectionRules = [evaluationRule]
onDemandRule.interfaceTypeMatch = NEOnDemandRuleInterfaceType.Any
manager.onDemandRules = [onDemandRule]
manager.onDemandEnabled = true
manager.enabled = true
manager.saveToPreferencesWithCompletionHandler { error in
if let vpnError = error {
print("vpn error in saving preferences : \(vpnError)")
return
}
}
}
}
I found this is buggy in even the latest iOS (10.3.1) and using NEVPNProtocolIKEv2. One moment it works, the next moment it doesn't want to start a VPN connection because it seems to misinterpret the ondemand rules and gives the error back saying the VPN profile is not enabled. I ended up with configuring the IKEv2 server (Strongswan) to push DNS settings with the "rightdns" option in /etc/ipsec.conf. This gives me the desired result of having the DNS requests redirected to a custom resolver.

Resources