summaryrefslogtreecommitdiff
path: root/swift/src
diff options
context:
space:
mode:
authorJoe George <joe@zeroc.com>2019-03-15 11:31:34 -0400
committerJoe George <joe@zeroc.com>2019-03-15 11:32:09 -0400
commit0c79bb767709ffec0a481d5159fe65f91837db59 (patch)
tree92cdda8e73d0ba1392846d424061df31a8ab5199 /swift/src
parentFixes for OutputStream and InputStream initialization (diff)
downloadice-0c79bb767709ffec0a481d5159fe65f91837db59.tar.bz2
ice-0c79bb767709ffec0a481d5159fe65f91837db59.tar.xz
ice-0c79bb767709ffec0a481d5159fe65f91837db59.zip
Add async proxy operations
Diffstat (limited to 'swift/src')
-rw-r--r--swift/src/Ice/Globals.swift5
-rw-r--r--swift/src/Ice/Proxy.swift219
-rw-r--r--swift/src/IceObjc/IceObjcLocalObject.h5
-rw-r--r--swift/src/IceObjc/IceObjcObjectPrx.h10
-rw-r--r--swift/src/IceObjc/IceObjcUtil.h1
-rw-r--r--swift/src/IceObjc/ObjectPrx.mm58
-rw-r--r--swift/src/IceObjc/Util.mm14
7 files changed, 267 insertions, 45 deletions
diff --git a/swift/src/Ice/Globals.swift b/swift/src/Ice/Globals.swift
index a493ef0863e..b5205a0f0c1 100644
--- a/swift/src/Ice/Globals.swift
+++ b/swift/src/Ice/Globals.swift
@@ -10,17 +10,18 @@
import IceObjc
// Factories are registed once, when this file is loaded
-let factoriesInitialized: Bool = {
+private let initialized: Bool = {
ICEUtil.registerFactories(localException: LocalExceptionFactory.self,
connectionInfo: ConnectionInfoFactory.self,
endpointInfo: EndpointInfoFactory.self)
+ return true
}()
public func initialize(args: StringSeq = [],
initData userInitData: InitializationData? = nil,
configFile: String? = nil) throws -> Communicator {
// Ensure factores are initialized
- precondition(factoriesInitialized)
+ precondition(initialized)
return try autoreleasepool {
var initData = userInitData ?? InitializationData()
diff --git a/swift/src/Ice/Proxy.swift b/swift/src/Ice/Proxy.swift
index 1342325f496..d98e5663781 100644
--- a/swift/src/Ice/Proxy.swift
+++ b/swift/src/Ice/Proxy.swift
@@ -97,49 +97,104 @@ public extension ObjectPrx {
hasOutParams: false)
}
+ func ice_pingAsync() -> Promise<Void> {
+ return impl._invokeAsync(operation: "ice_ping",
+ mode: OperationMode.Nonmutating,
+ twowayOnly: false,
+ inParams: nil,
+ hasOutParams: false) { _ in }
+ }
+
func ice_isA(id: String, context: Context? = nil) throws -> Bool {
let impl = self as! _ObjectPrxI
let os = impl._createOutputStream()
os.startEncapsulation()
os.write(id)
os.endEncapsulation()
- let ins = try impl._invoke(operation: "ice_isA",
+ let istr = try impl._invoke(operation: "ice_isA",
mode: .Nonmutating,
twowayOnly: true,
inParams: os,
hasOutParams: true,
context: context)
- try ins.startEncapsulation()
- let r: Bool = try ins.read()
- try ins.endEncapsulation()
+ try istr.startEncapsulation()
+ let r: Bool = try istr.read()
+ try istr.endEncapsulation()
return r
}
+ func ice_isAAsync(id: String, context: Context? = nil) -> Promise<Bool> {
+ let impl = self as! _ObjectPrxI
+ let os = impl._createOutputStream()
+ os.startEncapsulation()
+ os.write(id)
+ os.endEncapsulation()
+ return impl._invokeAsync(operation: "ice_isA",
+ mode: .Nonmutating,
+ twowayOnly: true,
+ inParams: os,
+ hasOutParams: true,
+ context: context) { istr in
+ try istr.startEncapsulation()
+ let r: Bool = try istr.read()
+ try istr.endEncapsulation()
+ return r
+ }
+ }
+
func ice_id(context: Context? = nil) throws -> String {
- let ins = try impl._invoke(operation: "ice_id",
+ let istr = try impl._invoke(operation: "ice_id",
mode: .Nonmutating,
twowayOnly: true,
inParams: nil,
hasOutParams: true,
context: context)
- try ins.startEncapsulation()
- let id: String = try ins.read()
- try ins.endEncapsulation()
+ try istr.startEncapsulation()
+ let id: String = try istr.read()
+ try istr.endEncapsulation()
return id
}
+ func ice_idAsync(context: Context? = nil) -> Promise<String> {
+ return impl._invokeAsync(operation: "ice_id",
+ mode: .Nonmutating,
+ twowayOnly: true,
+ inParams: nil,
+ hasOutParams: true,
+ context: context) { istr in
+ try istr.startEncapsulation()
+ let id: String = try istr.read()
+ try istr.endEncapsulation()
+ return id
+ }
+ }
+
func ice_ids(context: Context? = nil) throws -> StringSeq {
- let ins = try impl._invoke(operation: "ice_ids",
+ let istr = try impl._invoke(operation: "ice_ids",
mode: .Nonmutating,
twowayOnly: true,
inParams: nil,
hasOutParams: true,
context: context)
- try ins.startEncapsulation()
- let id: StringSeq = try ins.read()
- try ins.endEncapsulation()
+ try istr.startEncapsulation()
+ let id: StringSeq = try istr.read()
+ try istr.endEncapsulation()
return id
}
+
+ func ice_idsAsync(context: Context? = nil) -> Promise<StringSeq> {
+ return impl._invokeAsync(operation: "ice_ids",
+ mode: .Nonmutating,
+ twowayOnly: true,
+ inParams: nil,
+ hasOutParams: true,
+ context: context) { istr in
+ try istr.startEncapsulation()
+ let id: StringSeq = try istr.read()
+ try istr.endEncapsulation()
+ return id
+ }
+ }
}
open class _ObjectPrxI: ObjectPrx {
@@ -456,7 +511,7 @@ open class _ObjectPrxI: ObjectPrx {
return try fromICEObjectPrx(handle.ice_collocationOptimized(collocated))
}
- public static func ice_read(from ins: InputStream) throws -> Self? {
+ public static func ice_read(from istr: InputStream) throws -> Self? {
//
// Unmarshaling of proxies is done in C++. Since we don't know how big this proxy will
// be we pass the current buffer position and remaining buffer capacity.
@@ -465,9 +520,9 @@ open class _ObjectPrxI: ObjectPrx {
// The number of bytes consumed reading the proxy
var bytesRead: Int = 0
- let buf = ins.getBuffer()
- let encoding = ins.getEncoding()
- let communicator = ins.getCommunicator()
+ let buf = istr.getBuffer()
+ let encoding = istr.getEncoding()
+ let communicator = istr.getCommunicator()
//
// Returns Any which is either NSNull or ICEObjectPrx
@@ -507,38 +562,122 @@ open class _ObjectPrxI: ObjectPrx {
}
var ok = Bool()
- let ins = try InputStream(communicator: self.communicator,
- inputStream: handle.iceInvoke(op, mode: Int(mode.rawValue),
- inParams: inParams?.getBytes(),
- inSize: inParams?.getCount() ?? 0,
- context: context,
- returnValue: &ok))
+ let istrHandle = try handle.iceInvoke(op, mode: Int(mode.rawValue),
+ inParams: inParams?.getBytes(),
+ inSize: inParams?.getCount() ?? 0,
+ context: context,
+ returnValue: &ok)
+
+ let istr = InputStream(communicator: self.communicator, inputStream: istrHandle)
+
if self.isTwoway {
- if !ok {
- do {
- try ins.startEncapsulation()
- try ins.throwException()
- } catch let error as UserException {
- try ins.endEncapsulation()
- for exceptionType in exceptions {
- if exceptionType.isBase(of: type(of: error)) {
- throw error
- }
- }
- throw UnknownUserException(unknown: error.ice_id())
- }
- //
- // We let any all other error types propagate
- //
+ guard ok else {
+ throw try _ObjectPrxI.unmarshalUserException(stream: istr, exceptions: exceptions)
}
if !hasOutParams {
- try ins.skipEmptyEncapsulation()
+ try istr.skipEmptyEncapsulation()
}
}
+ return istr
+ }
+ }
+
+ public func _invokeAsync<T>(operation op: String,
+ mode: OperationMode,
+ twowayOnly: Bool,
+ inParams: OutputStream?,
+ hasOutParams: Bool,
+ exceptions: [UserException.Type] = [],
+ context: Context? = nil,
+ sent sendCallback: ((Bool) -> Void)? = nil,
+ unmarshalResult: @escaping ((InputStream) throws -> T)) -> Promise<T> {
- return ins
+ if twowayOnly, !self.isTwoway {
+ return Promise(error: TwowayOnlyException(operation: op))
}
+ //
+ // Create a pending promise. This way we can call into ObjC++ using the current thread
+ //
+ let (promise, resolver) = Promise<T>.pending()
+
+ //
+ // Response callback
+ //
+ func response(ok: Bool, inputStream istrHandle: ICEInputStream) {
+ do {
+ let istr = InputStream(communicator: self.communicator, inputStream: istrHandle)
+ if self.isTwoway {
+ guard ok else {
+ throw try _ObjectPrxI.unmarshalUserException(stream: istr, exceptions: exceptions)
+ }
+ if !hasOutParams {
+ try istr.skipEmptyEncapsulation()
+ }
+ }
+ try resolver.fulfill(unmarshalResult(istr))
+ } catch let error {
+ resolver.reject(error)
+ }
+ }
+
+ //
+ // Exception callback
+ //
+ func exception(error: Error) {
+ resolver.reject(error)
+ }
+
+ //
+ // Sent callback (optional)
+ //
+ var sent: ((Bool) -> Void)?
+
+ if let s = sendCallback {
+ sent = { (sentSynchronously: Bool) -> Void in
+ //
+ // Use PromiseKit's return queue if not nil, otherwise use call with the current thread
+ //
+ if let queue = PromiseKit.conf.Q.return {
+ queue.async {
+ s(sentSynchronously)
+ }
+ }
+ s(sentSynchronously)
+ }
+ }
+
+ do {
+ try autoreleasepool {
+ try handle.iceInvokeAsync(op, mode: Int(mode.rawValue),
+ inParams: inParams?.getBytes(),
+ inSize: inParams?.getCount() ?? 0,
+ context: context,
+ response: response, exception: exception, sent: sent)
+ }
+ } catch let error {
+ resolver.reject(error)
+ }
+
+ return promise
+
+ }
+
+ static func unmarshalUserException(stream istr: InputStream,
+ exceptions: [UserException.Type]) throws -> Error {
+ do {
+ try istr.startEncapsulation()
+ try istr.throwException()
+ } catch let error as UserException {
+ try istr.endEncapsulation()
+ for exceptionType in exceptions {
+ if exceptionType.isBase(of: type(of: error)) {
+ return error
+ }
+ }
+ return UnknownUserException(unknown: error.ice_id())
+ }
+ return UnknownUserException(unknown: "")
}
public static func checkedCast<ProxyImpl>(prx: ObjectPrx,
diff --git a/swift/src/IceObjc/IceObjcLocalObject.h b/swift/src/IceObjc/IceObjcLocalObject.h
index 56c923a826d..6d01bbd4a16 100644
--- a/swift/src/IceObjc/IceObjcLocalObject.h
+++ b/swift/src/IceObjc/IceObjcLocalObject.h
@@ -13,9 +13,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface ICELocalObject : NSObject
//
-// We hold a weak referece the (possile) Swift class which has a handle to
-// this local object. That way we can keep it in the cache and later recover
-// the Swift object.
+// We hold a weak referece to the (possile) Swift object which has a handle to
+// this ICELocalObject. That way we can keep recover the Swift object later.
//
@property (weak, nonatomic, nullable) id swiftRef;
-(instancetype) init ICE_SWIFT_UNAVAILABLE("");
diff --git a/swift/src/IceObjc/IceObjcObjectPrx.h b/swift/src/IceObjc/IceObjcObjectPrx.h
index 50b0ec0b2af..f690fa7300d 100644
--- a/swift/src/IceObjc/IceObjcObjectPrx.h
+++ b/swift/src/IceObjc/IceObjcObjectPrx.h
@@ -101,6 +101,16 @@ NS_ASSUME_NONNULL_BEGIN
returnValue:(bool*)returnValue
error:(NSError* _Nullable * _Nullable)error;
+-(BOOL) iceInvokeAsync:(NSString* _Nonnull)op
+ mode:(NSInteger)mode
+ inParams:(void* _Null_unspecified)inParams
+ inSize:(NSInteger)inSize
+ context:(NSDictionary* _Nullable)context
+ response:(void (^)(bool, ICEInputStream*))response
+ exception:(void (^)(NSError*))exception
+ sent:(void (^_Nullable)(bool))sent
+ error:(NSError* _Nullable * _Nullable)error;
+
-(bool) isEqual:(ICEObjectPrx* _Nullable)prx ;
@end
diff --git a/swift/src/IceObjc/IceObjcUtil.h b/swift/src/IceObjc/IceObjcUtil.h
index 64231bab8ec..2de45743a78 100644
--- a/swift/src/IceObjc/IceObjcUtil.h
+++ b/swift/src/IceObjc/IceObjcUtil.h
@@ -21,6 +21,7 @@ namespace IceSSL
class Certificate;
};
+NSError* convertException(const std::exception_ptr&);
NSError* convertException(const std::exception&);
template<typename T>
diff --git a/swift/src/IceObjc/ObjectPrx.mm b/swift/src/IceObjc/ObjectPrx.mm
index f78e23fe2bc..c2d19673c7b 100644
--- a/swift/src/IceObjc/ObjectPrx.mm
+++ b/swift/src/IceObjc/ObjectPrx.mm
@@ -586,6 +586,64 @@ encodingMinor:(uint8_t)minor
}
}
+-(BOOL) iceInvokeAsync:(NSString* _Nonnull)op
+ mode:(NSInteger)mode
+ inParams:(void* _Null_unspecified)inParams
+ inSize:(NSInteger)inSize
+ context:(NSDictionary* _Nullable)context
+ response:(void (^)(bool, ICEInputStream*))response
+ exception:(void (^)(NSError*))exception
+ sent:(void (^_Nullable)(bool))sent
+ error:(NSError* _Nullable * _Nullable)error
+{
+ std::pair<const Ice::Byte*, const Ice::Byte*> params(0, 0);
+ params.first = reinterpret_cast<Ice::Byte*>(inParams);
+ params.second = params.first + inSize;
+
+ try
+ {
+ Ice::Context ctx;
+ if(context)
+ {
+ fromNSDictionary(context, ctx);
+ }
+ else
+ {
+ ctx = Ice::noExplicitContext;
+ }
+
+ //
+ // It is possible to throw a CommunicatorDestroyedException
+ //
+ _prx->ice_invokeAsync(fromNSString(op), static_cast<Ice::OperationMode>(mode), params,
+ [response](bool ok, std::pair<const Ice::Byte*, const Ice::Byte*> outParams)
+ {
+ // Makes a copy
+ std::vector<Ice::Byte> r(outParams.first, outParams.second);
+ response(ok, [[ICEInputStream alloc] initWithBytes:std::move(r)]);
+ },
+ [exception](std::exception_ptr e)
+ {
+ exception(convertException(e));
+ },
+ [sent](bool sentSynchronously)
+ {
+ if(sent)
+ {
+ sent(sentSynchronously);
+ }
+ },
+ ctx);
+
+ return YES;
+ }
+ catch(const std::exception& ex)
+ {
+ *error = convertException(ex);
+ return NO;
+ }
+}
+
-(bool) isEqual:(ICEObjectPrx*)other
{
return Ice::targetEqualTo(_prx, other.prx);
diff --git a/swift/src/IceObjc/Util.mm b/swift/src/IceObjc/Util.mm
index d2d171b0412..7a2a88f1322 100644
--- a/swift/src/IceObjc/Util.mm
+++ b/swift/src/IceObjc/Util.mm
@@ -12,6 +12,20 @@
#import "IceObjcUtil.h"
NSError*
+convertException(const std::exception_ptr& excPtr)
+{
+ try
+ {
+ std::rethrow_exception(excPtr);
+ }
+ catch(const std::exception& exc)
+ {
+ return convertException(exc);
+ }
+ assert(false);
+}
+
+NSError*
convertException(const std::exception& exc)
{
if(dynamic_cast<const Ice::LocalException*>(&exc))