SwiftNIO: TCP Server not sending data back - swift-nio

I have written my own handler for SwiftNIO but I cannot get it to send anything.
class MyHandler: ChannelInboundHandler
{
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
public func channelRead(context: ChannelHandlerContext, data: NIOAny)
{
let message = "The weather is sunny.\n"
let length = message.utf8.count
var buffer = context.channel.allocator.buffer(capacity: length)
buffer.writeString(message)
let out = self.wrapOutboundOut(buffer)
context.write(out, promise: nil)
}
public func channelReadComplete(context: ChannelHandlerContext)
{
context.flush()
}
public func errorCaught(context: ChannelHandlerContext, error: Error)
{
print("error: ", error)
context.close(promise: nil)
}
}
If I just leave the channelRead function as below it successfully echoes the incoming text:
public func channelRead(context: ChannelHandlerContext, data: NIOAny)
{
context.write(data, promise: nil)
}
What am I doing wrong?

You're not doing anything wrong, this should work just fine. It'll send back The weather is sunny.\n every time any data is received.
I also tried it and it works:
$ nc localhost 9999
How's the weather?
The weather is sunny.
How are you?
The weather is sunny.
The complete code I used was
import NIO
class MyHandler: ChannelInboundHandler
{
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
public func channelRead(context: ChannelHandlerContext, data: NIOAny)
{
let message = "The weather is sunny.\n"
let length = message.utf8.count
var buffer = context.channel.allocator.buffer(capacity: length)
buffer.writeString(message)
let out = self.wrapOutboundOut(buffer)
context.write(out, promise: nil)
}
public func channelReadComplete(context: ChannelHandlerContext)
{
context.flush()
}
public func errorCaught(context: ChannelHandlerContext, error: Error)
{
print("error: ", error)
context.close(promise: nil)
}
}
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
defer {
try! group.syncShutdownGracefully()
}
let bootstrap = ServerBootstrap(group: group)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
channel.pipeline.addHandler(MyHandler())
}
let serverChannel = try bootstrap.bind(host: "localhost", port: 9999).wait()
try serverChannel.closeFuture.wait()

Related

Swift Does not see data

I am trying to parse the data and display on the screen but i am getting " Value of type 'EmployeeData' has no member 'employee_name' "
What i am missing ?
I created my struct, parsed data and tried to divide into two parts. first part will be related with listing, second part is all data.
struct EmployeeData: Codable {
var data: Employee
var status: String
}
struct Employee: Codable {
var employee_name: String
var employee_salary: String
var employee_age: String
}
class WebServices {
func getData(completion: #escaping (EmployeeData?) -> ()){
guard let url = URL(string:"http://dummy.restapiexample.com/api/v1/employees")
else { fatalError("There is error!") }
URLSession.shared.dataTask(with: url) { (data, response,error) in
guard let data = data, error == nil else {
DispatchQueue.main.async{
completion(nil)
}
return
}
let empleyees = try? JSONDecoder().decode(EmployeeData.self, from: data)
DispatchQueue.main.async {
completion(empleyees)
}
}.resume()
}
}
class MVDesingnListView: ObservableObject {
}
struct MVDesignCellView {
let employeeDatas: EmployeeData
init(employeeDatas: EmployeeData) {
self.employeeDatas = employeeDatas
}
var employee_name: String {
self.employeeDatas.employee_name
}
}
The compiler is all right. Your struct EmployeeData has no member employee_name.
You need to go to the employee first, to get her name:
var employee_name: String {
self.employeeDatas.data.employee_name
}
should do the job.

Variable value get empty in iOS swift

I have create computed property for store the strTokenValue and send it to the web services.
private var strTokenValue = String()
var tokenValue: String {
get {
if strTokenValue != "" {
return strTokenValue
}
else {
if let token = StrongBoxController.sharedInstance.keychainStore.unarchive(objectForKey: "TokenValue") as? Data {
strTokenValue = StrongBoxController.sharedInstance.convertDataToString(value: token)
return strTokenValue
}
else {
return ""
}
}
}
set {
strTokenValue = ""
StrongBoxController.sharedInstance.saveValues(value: "\(newValue)", key: “TokenValue”)
}
}
We have send every user action Asynchronously and we have not wait for success response for track function web services, So i have not added success and failure response in the below code.
func track(actionTaken: String,incidentNumber: String,message: String,completion:#escaping(_ success: Bool, _ error: String,_ actionTakenName: String) -> Void ) {
DispatchQueue.global(qos: .background).async {
let url = "\(ServerCommunication.sharedInstance.getDomainBaseUrl())api/track"
let parameters = [
“token_value” : self.tokenValue,
"device_os":"iOS",
"device_type": UIDevice.modelName,
"action_taken": actionTaken,
"message" : message,
]
}
}
We have called the one more web service to send the image and tokenValue.
Request:
“token_value” : “”,
"device_os":"iOS",
"device_type": “iPhone X”,
"action_taken": “Image captured”,
"message" : “”,
func convertDataToString(value: Data) -> String {
return String(decoding: value, as: UTF8.self)
}
public func unarchive(objectForKey key:String) -> Any? {
guard let data = self.data(forKey: key) else {
return nil
}
let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)
return unarchiver.decodeObject(forKey: key)
}
#objc func saveValues(value : String, key: String) {
_ = self.keychainStore.archive(convertStringToData(value: value), key: key, accessibility: kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
}
Both web services called simultaneously and “tokenValue” get empty in trackActions web services in some scenarios
It seems the problem is that you save data using convertStringToData which doesn't probably use convertStringToData. I think so because of convertDataToString doesn't use NSKeyedAarchiver.
In order to resolve, you should use unarchive.
To save the data use
func convertDataToString(value: Data) -> String? {
return String(data: value, encoding: .utf8)
}
func convertStringToData(value: String) -> Data? {
return value.data(using: .utf8)
}
and
keychainStore.archive(convertStringToData(value: value), key: key, accessibility: kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
stored = convertDataToString(StrongBoxController.sharedInstance.keychainStore.unarchive(objectForKey: "TokenValue"))

Can't access model object data outside the alamofire request scope while populating api data on badoo/Chatto chat text

Previously I successfully access model objects anywhere in the class but while populating data on badoo/chatto text view I am stuck.
I am integrating chat message api into badoo chat view
Basically, the issue is alamofire response is not getting outside of the scope.
Did I try with compilation handler but no luck? Is there any way to resolve this issue?
Thanks in advance .
Here is code snippet :
import Foundation
import Chatto
import ChattoAdditions
import SwiftyJSON
import Alamofire
class DemoChatMessageFactory {
public static var chats = [ChatModel]()
class func makeMessage(_ uid:String) -> DemoTextMessageModel{
print("uid makeMessage : \(uid)")
return self.makeMessageData(uid, isIncoming:false)
}
class func makeMessageData(_ uid: String,isIncoming:Bool) -> DemoTextMessageModel {
if isIncoming == true{
return self.makeTextFinalMessage(uid, isIncoming:isIncoming)
} else {
return self.makeTextFinalMessage(uid, isIncoming: isIncoming)
}
}
public class func makeTextMessage(_ uid: String, isIncoming: Bool,text:String) -> DemoTextMessageModel {
let messageModel = self.makeMessageModel(uid, isIncoming: isIncoming,
type: TextMessageModel<MessageModel>.chatItemType)
let textMessageModel = DemoTextMessageModel(messageModel:messageModel,
text: text)
return textMessageModel
}
public class func makeTextFinalMessage(_ uid: String, isIncoming: Bool) -> DemoTextMessageModel {
var text = String()
var uidInt = Int(uid)
print("string uid 121 \(uid)")
print("print is Incomming data or not 1: \(isIncoming)")
print("uid count :\(uid.count)")
let urlString = "[My message Api]"
Alamofire.request(urlString, method: .get).validate().responseJSON {
(response) -> Void in
if let value = response.data {
do {
let json = try JSON(data: value)
if let dictionnary = json.dictionaryObject {
if let messageArray = dictionnary["message"] as?[[String: Any]] {
self.chats.removeAll()
for arr in messageArray {
self.chats.append(ChatModel(ChatListJSON: arr))
}
}
}
} catch {
print("cannot convert to Json")
}
}
print("print int 122 : \(uidInt!)")
print("Chat List Id DemoChatMessageFactory \(self.chats[uidInt!].chatId)")
print("chat message: \(String(describing: uidInt!)) th \(self.chats[uidInt!].chatMessage)")
self.textData = "\(self.chats[uidInt!].chatMessage)"
self.makeTextMessage(uid, isIncoming: isIncoming, text:self.textData) //Here I am bale to pass textData but ouside the Alamofire block can't access
}
//Here getting empty values
print("uid makeTextFinalMessage \(uid)")
print("in coming makeTextFinalMessage \(isIncoming)")
print("text makeTextFinalMessage \(text)")
//chat count also getting zero count
print("chat count final text\(chats.count)")
print("print chat count : \(self.chats.count)")
return self.makeTextMessage(uid, isIncoming: isIncoming, text:self.textData)
}
}
Test for completion handler
public var res: Any = ""
func getAllChatData(completionhandler:#escaping ([String: Any]?) -> ()){
let URL = "my api"
Alamofire.request(URL).responseJSON {
response in
if let json = response.result.value as? [String: Any] {
completionhandler(json, nil)
}
else if let error = response.result.error as Error? {
completionhandler(nil, error)
}
}
}
and call using like below inside the function
DemoChatMessageFactory.getAllChatData {
(result) in
res = result
print("response (res)")
}
please suggest me the proper way to alamofire with compilation handler
This is an example of converting all methods using the result of asynchronous call. As I have never used Chatto and you are not showing all the types in your code, so you may need to modify many parts of my code, but I believe you can see what you need to do with this code.
import Foundation
import Chatto
import ChattoAdditions
import SwiftyJSON
import Alamofire
class DemoChatMessageFactory {
public static var chats = [ChatModel]()
class func requestMessage(_ uid:String,
completion: #escaping (DemoTextMessageModel?, Error?)->Void) {
print("uid makeMessage : \(uid)")
self.requestMessageData(uid, isIncoming: false) { (model, error) in
completion(model, error)
}
}
class func requestMessageData(_ uid: String, isIncoming: Bool,
completion: #escaping (DemoTextMessageModel?, Error?)->Void) {
if isIncoming {
//...put any code needed when isIncoming is true
self.requestTextFinalMessage(uid, isIncoming: isIncoming) { model in
completion(model, error)
}
} else {
//...put any code needed when isIncoming is false
self.requestTextFinalMessage(uid, isIncoming: isIncoming) { model in
completion(model, error)
}
}
}
public class func makeTextMessage(_ uid: String, isIncoming: Bool, text: String) -> DemoTextMessageModel {
let messageModel = self.makeMessageModel(uid, isIncoming: isIncoming,
type: TextMessageModel<MessageModel>.chatItemType)
let textMessageModel = DemoTextMessageModel(messageModel:messageModel,
text: text)
return textMessageModel
}
public class func requestTextFinalMessage(_ uid: String, isIncoming: Bool,
completion: #escaping (DemoTextMessageModel?, Error?)->Void) {
var text = String()
var uidInt = Int(uid)
print("string uid 121 \(uid)")
print("print is Incomming data or not 1: \(isIncoming)")
print("uid count :\(uid.count)")
let urlString = "[My message Api]"
Alamofire.request(urlString, method: .get).validate().responseJSON {
(response) -> Void in
if let value = response.data {
do {
let json = try JSON(data: value)
if let dictionnary = json.dictionaryObject {
if let messageArray = dictionnary["message"] as?[[String: Any]] {
self.chats.removeAll()
for arr in messageArray {
self.chats.append(ChatModel(ChatListJSON: arr))
}
}
}
print("print int 122 : \(uidInt!)")
print("Chat List Id DemoChatMessageFactory \(self.chats[uidInt!].chatId)")
print("chat message: \(String(describing: uidInt!)) th \(self.chats[uidInt!].chatMessage)")
self.textData = "\(self.chats[uidInt!].chatMessage)"
completion(self.makeTextMessage(uid, isIncoming: isIncoming, text: self.textData), nil)
} catch {
print("cannot convert to Json")
completion(nil, error)
}
} else {
//better generate an error case result, and call completion.
//...
}
}
}
}
I changed some method names from make... to request... to show clarify they are asynchronous methods.
And the usage, if you intend to use your original code as:
let model = DemoChatMessageFactory.makeMessage(uid)
//Do some UI updates using `model`...
You may need to use asynchronous methods like:
DemoChatMessageFactory.requestMessage(uid) { (model, error) in
if let model = model {
//Do some UI updates using `model`...
} else {
//Do something for the error...
}
}

Apple File Application perform "Move" action via file provider extension my extention display disable

In my file provider extension i want to perform move operation in my NoteProvider extension.
I can move any file via Drag operation above any folder it works properly But when i try to "Move" via Action display in bellow screen at that time screen2 display and other extension are enable but my NotProvider Extension was disable.
My code are FileProviderItem
class FileProviderItem: NSObject, NSFileProviderItem {
public var id: String?
public var name: String?
var childItemCount : NSNumber?
var documentSize: NSNumber?
var creationDate : Date?
var contentModificationDate : Date?
var lastUsedDate: Date?
var isDownloaded: Bool = false
public var fTypeIdentifier: String?
var pid : NSFileProviderItemIdentifier!
var parentItemIdentifier: NSFileProviderItemIdentifier {
return pid
}
var typeIdentifier: String {
return fTypeIdentifier! // for folder = "public.folder", for file = file type UTI
}
var itemIdentifier: NSFileProviderItemIdentifier {
return NSFileProviderItemIdentifier(self.id!)
}
var filename: String {
return self.name!
}
override init() {
}
override func isEqual(_ object: Any?) -> Bool {
if let obj = object as? FileProviderItem {
if self.itemIdentifier == obj.itemIdentifier {
return true
}
}
return false
}
var capabilities: NSFileProviderItemCapabilities {
return .allowsAll
}
}
For FileProviderExtension
class FileProviderExtension: NSFileProviderExtension {
override func item(for identifier: NSFileProviderItemIdentifier) throws -> NSFileProviderItem {
// resolve the given identifier to a record in the model
// db = Array of NSFileProviderItem
for i in db {
if i.itemIdentifier.rawValue == identifier.rawValue {
return i
}
}
// TODO: implement the actual lookup
throw NSError(domain: NSCocoaErrorDomain, code: NSNotFound, userInfo:[:])
}
override func importDocument(at fileURL: URL, toParentItemIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, completionHandler: #escaping (NSFileProviderItem?, Error?) -> Void) {
print("importDocument :- \(fileURL) parentItemIdentifier = \(parentItemIdentifier)")
completionHandler(nil, nil)
}
override func reparentItem(withIdentifier itemIdentifier: NSFileProviderItemIdentifier, toParentItemWithIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, newName: String?, completionHandler: #escaping (NSFileProviderItem?, Error?) -> Void) {
print("reparentItem :- \(itemIdentifier) parentItemIdentifier = \(parentItemIdentifier) newName = \(String(describing: newName))")
guard let item = try? item(for: itemIdentifier) as? FileProviderItem else {
completionHandler(nil, NSFileProviderError(.noSuchItem))
return
}
item?.pid = NSFileProviderItemIdentifier(rawValue: parentItemIdentifier.rawValue)
//item?.name = newName
completionHandler(item, nil)
}
}
NoteProvider(FileProvider) .plist file image
return NSFileProviderItem instance in itemForIdentifier method for identifier NSFileProviderRootContainerItemIdentifier. If you return nil for root identifier, app wont be enabled in move operation.

Losing reference to a property of an instance in Swift

I'm encountering a problem where a property of an instance of a class I've created is seemingly losing reference to one its values.
Essentially I have a class like this:
class Channel {
var callbacks: [String: (JSON) -> Void]
var subscribed = false
let name: String
init(name: String) {
self.name = name
self.callbacks = [:]
}
func bind(eventName: String, callback: (JSON) -> Void) {
self.callbacks[eventName] = callback
}
func handleEvent(eventName: String, eventData: String) {
if let cb = self.callbacks[eventName] {
let json = JSON(object: eventData)
cb(json)
}
}
}
and then inside a ViewController I have the following code:
class ViewController: UIViewController {
let wSock = wSocket(key: "afa4d38348f89ba9c398")
func channelSetup() {
var ch = wSock.subscribe("test-channel")
ch.bind("test-event", { (data: JSON) -> Void in
println("I'm the callback getting called")
})
println(ch.callbacks)
}
override func viewDidLoad() {
super.viewDidLoad()
channelSetup()
}
}
In the println of ch.callbacks it shows that there is a key-value pair in the dictionary.
However, when the channel receives an event later on when there is a message received over the socket, the callback is no longer there. In terms of code, here is the code in full:
import UIKit
class ViewController: UIViewController {
let wSock = wSocketClient(key: "afa4d38348f89ba9c398")
func channelSetup() {
var ch = wSock.subscribe("test-channel")
ch.bind("test-event", { (data: JSON) -> Void in
println("I'm the callback getting called")
})
println(ch.callbacks)
}
override func viewDidLoad() {
super.viewDidLoad()
channelSetup()
}
}
class wSocketClient {
let connection: Connection
init(key: String, encrypted: Bool = false) {
var url = "SOCKET_URL"
connection = Connection(url: url)
}
func subscribe(channelName: String) -> Channel {
return self.connection.addChannel(channelName)
}
func connect() {
self.connection.open()
}
}
class Connection: WebSocketDelegate {
let url: String
lazy var socket: WebSocket = { [unowned self] in
return self.connectInternal()
}()
let connected = false
var channels = Channels()
init(url: String) {
self.url = url
}
func addChannel(channelName: String) -> Channel {
return Channel(name: channelName)
}
func open() {
if self.connected {
return
} else {
self.socket = connectInternal()
}
}
func connectInternal() -> WebSocket {
let ws = WebSocket(url: NSURL(string: self.url)!)
ws.delegate = self
ws.connect()
return ws
}
func websocketDidReceiveMessage(text: String) {
let data = (text as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let json = JSON(data: data!)
if let channelName = json["channel"].stringValue {
if let internalChannel = self.channels.find(channelName) {
if let eName = json["event"].stringValue {
if let eData = json["data"].stringValue {
internalChannel.handleEvent(eName, eventData: eData) // this is the part of the code where the channel should eventually call the callback
}
}
}
}
}
}
class Channel {
var callbacks: [String: (JSON) -> Void]
var subscribed = false
let name: String
init(name: String) {
self.name = name
self.callbacks = [:]
}
func bind(eventName: String, callback: (JSON) -> Void) {
self.callbacks[eventName] = callback
}
func handleEvent(eventName: String, eventData: String) {
if let cb = self.callbacks[eventName] { // here self.callbacks is empty and the callback has disappeared
let json = JSON(object: eventData)
cb(json)
}
}
}
class Channels {
var channels = [String: Channel]()
func add(channelName: String) -> Channel {
if let channel = self.channels[channelName] {
return channel
} else {
let newChannel = Channel(name: channelName)
self.channels[channelName] = newChannel
return newChannel
}
}
func find(channelName: String) -> Channel? {
return self.channels[channelName]
}
}
So basically when the WebSocket receives some data that is for the given channel, it should check for the event name, and if there is a callback with that event name, call the callback associated to that event name. However, the channel apparently has no callbacks when the handleEvent method is called, even though at the bottom of viewDidLoad it shows as having a callback in the callbacks property for the channel.
Any ideas as to where / why the callback is disappearing?
Update
I've now tried moving the definition of the channel, ch outside of the channelSetup function so it's like this, but with no luck:
class ViewController: UIViewController {
let wSock = wSocket(key: "afa4d38348f89ba9c398")
var ch: Channel = nil
func channelSetup() {
ch = wSock.subscribe("test-channel")
ch.bind("test-event", { (data: JSON) -> Void in
println("I'm the callback getting called")
})
println(ch.callbacks)
}
override func viewDidLoad() {
super.viewDidLoad()
channelSetup()
}
}
I've solved this but not because it was something going on in Swift that I didn't understand. Instead it was just that the way that I had setup the code meant that there were duplicate channel objects being created and the callback was being added to only one of the channels.

Resources