@synonymdev/react-native-pubky 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,9 +29,10 @@ import java.nio.ByteOrder
29
29
  import java.nio.CharBuffer
30
30
  import java.nio.charset.CodingErrorAction
31
31
  import java.util.concurrent.ConcurrentHashMap
32
- import kotlin.coroutines.resume
33
- import kotlinx.coroutines.CancellableContinuation
34
- import kotlinx.coroutines.suspendCancellableCoroutine
32
+ import java.util.concurrent.atomic.AtomicBoolean
33
+ import java.util.concurrent.atomic.AtomicLong
34
+ import java.util.concurrent.locks.ReentrantLock
35
+ import kotlin.concurrent.withLock
35
36
 
36
37
  // This is a helper for safely working with byte buffers returned from the Rust code.
37
38
  // A rust-owned buffer is represented by its capacity, its current length, and a
@@ -380,15 +381,29 @@ internal interface _UniFFILib : Library {
380
381
  .also { lib: _UniFFILib ->
381
382
  uniffiCheckContractApiVersion(lib)
382
383
  uniffiCheckApiChecksums(lib)
383
- uniffiRustFutureContinuationCallback.register(lib)
384
+ FfiConverterTypeEventListener.register(lib)
384
385
  }
385
386
  }
386
387
  }
387
388
 
389
+ fun uniffi_pubkymobile_fn_free_eventnotifier(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
390
+ ): Unit
391
+ fun uniffi_pubkymobile_fn_init_callback_eventlistener(`callbackStub`: ForeignCallback,_uniffi_out_err: RustCallStatus,
392
+ ): Unit
388
393
  fun uniffi_pubkymobile_fn_func_auth(`url`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
389
394
  ): RustBuffer.ByValue
390
- fun uniffi_pubkymobile_fn_func_get(`url`: RustBuffer.ByValue,
391
- ): Pointer
395
+ fun uniffi_pubkymobile_fn_func_create_recovery_file(`secretKey`: RustBuffer.ByValue,`passphrase`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
396
+ ): RustBuffer.ByValue
397
+ fun uniffi_pubkymobile_fn_func_decrypt_recovery_file(`recoveryFile`: RustBuffer.ByValue,`passphrase`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
398
+ ): RustBuffer.ByValue
399
+ fun uniffi_pubkymobile_fn_func_delete_file(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
400
+ ): RustBuffer.ByValue
401
+ fun uniffi_pubkymobile_fn_func_generate_secret_key(_uniffi_out_err: RustCallStatus,
402
+ ): RustBuffer.ByValue
403
+ fun uniffi_pubkymobile_fn_func_get(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
404
+ ): RustBuffer.ByValue
405
+ fun uniffi_pubkymobile_fn_func_get_public_key_from_secret_key(`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
406
+ ): RustBuffer.ByValue
392
407
  fun uniffi_pubkymobile_fn_func_list(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
393
408
  ): RustBuffer.ByValue
394
409
  fun uniffi_pubkymobile_fn_func_parse_auth_url(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
@@ -397,18 +412,24 @@ internal interface _UniFFILib : Library {
397
412
  ): RustBuffer.ByValue
398
413
  fun uniffi_pubkymobile_fn_func_publish_https(`recordName`: RustBuffer.ByValue,`target`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
399
414
  ): RustBuffer.ByValue
400
- fun uniffi_pubkymobile_fn_func_put(`url`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,
401
- ): Pointer
415
+ fun uniffi_pubkymobile_fn_func_put(`url`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
416
+ ): RustBuffer.ByValue
417
+ fun uniffi_pubkymobile_fn_func_remove_event_listener(_uniffi_out_err: RustCallStatus,
418
+ ): Unit
402
419
  fun uniffi_pubkymobile_fn_func_resolve(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
403
420
  ): RustBuffer.ByValue
404
421
  fun uniffi_pubkymobile_fn_func_resolve_https(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
405
422
  ): RustBuffer.ByValue
406
- fun uniffi_pubkymobile_fn_func_sign_in(`secretKey`: RustBuffer.ByValue,
407
- ): Pointer
408
- fun uniffi_pubkymobile_fn_func_sign_out(`secretKey`: RustBuffer.ByValue,
409
- ): Pointer
410
- fun uniffi_pubkymobile_fn_func_sign_up(`secretKey`: RustBuffer.ByValue,`homeserver`: RustBuffer.ByValue,
411
- ): Pointer
423
+ fun uniffi_pubkymobile_fn_func_session(`pubky`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
424
+ ): RustBuffer.ByValue
425
+ fun uniffi_pubkymobile_fn_func_set_event_listener(`listener`: Long,_uniffi_out_err: RustCallStatus,
426
+ ): Unit
427
+ fun uniffi_pubkymobile_fn_func_sign_in(`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
428
+ ): RustBuffer.ByValue
429
+ fun uniffi_pubkymobile_fn_func_sign_out(`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
430
+ ): RustBuffer.ByValue
431
+ fun uniffi_pubkymobile_fn_func_sign_up(`secretKey`: RustBuffer.ByValue,`homeserver`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
432
+ ): RustBuffer.ByValue
412
433
  fun ffi_pubkymobile_rustbuffer_alloc(`size`: Int,_uniffi_out_err: RustCallStatus,
413
434
  ): RustBuffer.ByValue
414
435
  fun ffi_pubkymobile_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus,
@@ -525,8 +546,18 @@ internal interface _UniFFILib : Library {
525
546
  ): Unit
526
547
  fun uniffi_pubkymobile_checksum_func_auth(
527
548
  ): Short
549
+ fun uniffi_pubkymobile_checksum_func_create_recovery_file(
550
+ ): Short
551
+ fun uniffi_pubkymobile_checksum_func_decrypt_recovery_file(
552
+ ): Short
553
+ fun uniffi_pubkymobile_checksum_func_delete_file(
554
+ ): Short
555
+ fun uniffi_pubkymobile_checksum_func_generate_secret_key(
556
+ ): Short
528
557
  fun uniffi_pubkymobile_checksum_func_get(
529
558
  ): Short
559
+ fun uniffi_pubkymobile_checksum_func_get_public_key_from_secret_key(
560
+ ): Short
530
561
  fun uniffi_pubkymobile_checksum_func_list(
531
562
  ): Short
532
563
  fun uniffi_pubkymobile_checksum_func_parse_auth_url(
@@ -537,16 +568,24 @@ internal interface _UniFFILib : Library {
537
568
  ): Short
538
569
  fun uniffi_pubkymobile_checksum_func_put(
539
570
  ): Short
571
+ fun uniffi_pubkymobile_checksum_func_remove_event_listener(
572
+ ): Short
540
573
  fun uniffi_pubkymobile_checksum_func_resolve(
541
574
  ): Short
542
575
  fun uniffi_pubkymobile_checksum_func_resolve_https(
543
576
  ): Short
577
+ fun uniffi_pubkymobile_checksum_func_session(
578
+ ): Short
579
+ fun uniffi_pubkymobile_checksum_func_set_event_listener(
580
+ ): Short
544
581
  fun uniffi_pubkymobile_checksum_func_sign_in(
545
582
  ): Short
546
583
  fun uniffi_pubkymobile_checksum_func_sign_out(
547
584
  ): Short
548
585
  fun uniffi_pubkymobile_checksum_func_sign_up(
549
586
  ): Short
587
+ fun uniffi_pubkymobile_checksum_method_eventlistener_on_event_occurred(
588
+ ): Short
550
589
  fun ffi_pubkymobile_uniffi_contract_version(
551
590
  ): Int
552
591
 
@@ -567,7 +606,22 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
567
606
  if (lib.uniffi_pubkymobile_checksum_func_auth() != 61378.toShort()) {
568
607
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
569
608
  }
570
- if (lib.uniffi_pubkymobile_checksum_func_get() != 5395.toShort()) {
609
+ if (lib.uniffi_pubkymobile_checksum_func_create_recovery_file() != 55903.toShort()) {
610
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
611
+ }
612
+ if (lib.uniffi_pubkymobile_checksum_func_decrypt_recovery_file() != 59688.toShort()) {
613
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
614
+ }
615
+ if (lib.uniffi_pubkymobile_checksum_func_delete_file() != 57905.toShort()) {
616
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
617
+ }
618
+ if (lib.uniffi_pubkymobile_checksum_func_generate_secret_key() != 63116.toShort()) {
619
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
620
+ }
621
+ if (lib.uniffi_pubkymobile_checksum_func_get() != 21596.toShort()) {
622
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
623
+ }
624
+ if (lib.uniffi_pubkymobile_checksum_func_get_public_key_from_secret_key() != 23603.toShort()) {
571
625
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
572
626
  }
573
627
  if (lib.uniffi_pubkymobile_checksum_func_list() != 8522.toShort()) {
@@ -582,7 +636,10 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
582
636
  if (lib.uniffi_pubkymobile_checksum_func_publish_https() != 14705.toShort()) {
583
637
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
584
638
  }
585
- if (lib.uniffi_pubkymobile_checksum_func_put() != 47594.toShort()) {
639
+ if (lib.uniffi_pubkymobile_checksum_func_put() != 51107.toShort()) {
640
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
641
+ }
642
+ if (lib.uniffi_pubkymobile_checksum_func_remove_event_listener() != 6794.toShort()) {
586
643
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
587
644
  }
588
645
  if (lib.uniffi_pubkymobile_checksum_func_resolve() != 18303.toShort()) {
@@ -591,62 +648,27 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
591
648
  if (lib.uniffi_pubkymobile_checksum_func_resolve_https() != 34593.toShort()) {
592
649
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
593
650
  }
594
- if (lib.uniffi_pubkymobile_checksum_func_sign_in() != 53969.toShort()) {
651
+ if (lib.uniffi_pubkymobile_checksum_func_session() != 65177.toShort()) {
595
652
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
596
653
  }
597
- if (lib.uniffi_pubkymobile_checksum_func_sign_out() != 32961.toShort()) {
654
+ if (lib.uniffi_pubkymobile_checksum_func_set_event_listener() != 19468.toShort()) {
598
655
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
599
656
  }
600
- if (lib.uniffi_pubkymobile_checksum_func_sign_up() != 28083.toShort()) {
657
+ if (lib.uniffi_pubkymobile_checksum_func_sign_in() != 21006.toShort()) {
601
658
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
602
659
  }
603
- }
604
-
605
- // Async support
606
- // Async return type handlers
607
-
608
- internal const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toShort()
609
- internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toShort()
610
-
611
- internal val uniffiContinuationHandleMap = UniFfiHandleMap<CancellableContinuation<Short>>()
612
-
613
- // FFI type for Rust future continuations
614
- internal object uniffiRustFutureContinuationCallback: UniFffiRustFutureContinuationCallbackType {
615
- override fun callback(continuationHandle: USize, pollResult: Short) {
616
- uniffiContinuationHandleMap.remove(continuationHandle)?.resume(pollResult)
660
+ if (lib.uniffi_pubkymobile_checksum_func_sign_out() != 59116.toShort()) {
661
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
617
662
  }
618
-
619
- internal fun register(lib: _UniFFILib) {
620
- lib.ffi_pubkymobile_rust_future_continuation_callback_set(this)
663
+ if (lib.uniffi_pubkymobile_checksum_func_sign_up() != 58756.toShort()) {
664
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
621
665
  }
622
- }
623
-
624
- internal suspend fun<T, F, E: Exception> uniffiRustCallAsync(
625
- rustFuture: Pointer,
626
- pollFunc: (Pointer, USize) -> Unit,
627
- completeFunc: (Pointer, RustCallStatus) -> F,
628
- freeFunc: (Pointer) -> Unit,
629
- liftFunc: (F) -> T,
630
- errorHandler: CallStatusErrorHandler<E>
631
- ): T {
632
- try {
633
- do {
634
- val pollResult = suspendCancellableCoroutine<Short> { continuation ->
635
- pollFunc(
636
- rustFuture,
637
- uniffiContinuationHandleMap.insert(continuation)
638
- )
639
- }
640
- } while (pollResult != UNIFFI_RUST_FUTURE_POLL_READY);
641
-
642
- return liftFunc(
643
- rustCallWithError(errorHandler, { status -> completeFunc(rustFuture, status) })
644
- )
645
- } finally {
646
- freeFunc(rustFuture)
666
+ if (lib.uniffi_pubkymobile_checksum_method_eventlistener_on_event_occurred() != 39865.toShort()) {
667
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
647
668
  }
648
669
  }
649
670
 
671
+ // Async support
650
672
 
651
673
  // Public interface members begin here.
652
674
 
@@ -706,6 +728,384 @@ public object FfiConverterString: FfiConverter<String, RustBuffer.ByValue> {
706
728
  }
707
729
 
708
730
 
731
+ // Interface implemented by anything that can contain an object reference.
732
+ //
733
+ // Such types expose a `destroy()` method that must be called to cleanly
734
+ // dispose of the contained objects. Failure to call this method may result
735
+ // in memory leaks.
736
+ //
737
+ // The easiest way to ensure this method is called is to use the `.use`
738
+ // helper method to execute a block and destroy the object at the end.
739
+ interface Disposable {
740
+ fun destroy()
741
+ companion object {
742
+ fun destroy(vararg args: Any?) {
743
+ args.filterIsInstance<Disposable>()
744
+ .forEach(Disposable::destroy)
745
+ }
746
+ }
747
+ }
748
+
749
+ inline fun <T : Disposable?, R> T.use(block: (T) -> R) =
750
+ try {
751
+ block(this)
752
+ } finally {
753
+ try {
754
+ // N.B. our implementation is on the nullable type `Disposable?`.
755
+ this?.destroy()
756
+ } catch (e: Throwable) {
757
+ // swallow
758
+ }
759
+ }
760
+
761
+ // The base class for all UniFFI Object types.
762
+ //
763
+ // This class provides core operations for working with the Rust `Arc<T>` pointer to
764
+ // the live Rust struct on the other side of the FFI.
765
+ //
766
+ // There's some subtlety here, because we have to be careful not to operate on a Rust
767
+ // struct after it has been dropped, and because we must expose a public API for freeing
768
+ // the Kotlin wrapper object in lieu of reliable finalizers. The core requirements are:
769
+ //
770
+ // * Each `FFIObject` instance holds an opaque pointer to the underlying Rust struct.
771
+ // Method calls need to read this pointer from the object's state and pass it in to
772
+ // the Rust FFI.
773
+ //
774
+ // * When an `FFIObject` is no longer needed, its pointer should be passed to a
775
+ // special destructor function provided by the Rust FFI, which will drop the
776
+ // underlying Rust struct.
777
+ //
778
+ // * Given an `FFIObject` instance, calling code is expected to call the special
779
+ // `destroy` method in order to free it after use, either by calling it explicitly
780
+ // or by using a higher-level helper like the `use` method. Failing to do so will
781
+ // leak the underlying Rust struct.
782
+ //
783
+ // * We can't assume that calling code will do the right thing, and must be prepared
784
+ // to handle Kotlin method calls executing concurrently with or even after a call to
785
+ // `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`.
786
+ //
787
+ // * We must never allow Rust code to operate on the underlying Rust struct after
788
+ // the destructor has been called, and must never call the destructor more than once.
789
+ // Doing so may trigger memory unsafety.
790
+ //
791
+ // If we try to implement this with mutual exclusion on access to the pointer, there is the
792
+ // possibility of a race between a method call and a concurrent call to `destroy`:
793
+ //
794
+ // * Thread A starts a method call, reads the value of the pointer, but is interrupted
795
+ // before it can pass the pointer over the FFI to Rust.
796
+ // * Thread B calls `destroy` and frees the underlying Rust struct.
797
+ // * Thread A resumes, passing the already-read pointer value to Rust and triggering
798
+ // a use-after-free.
799
+ //
800
+ // One possible solution would be to use a `ReadWriteLock`, with each method call taking
801
+ // a read lock (and thus allowed to run concurrently) and the special `destroy` method
802
+ // taking a write lock (and thus blocking on live method calls). However, we aim not to
803
+ // generate methods with any hidden blocking semantics, and a `destroy` method that might
804
+ // block if called incorrectly seems to meet that bar.
805
+ //
806
+ // So, we achieve our goals by giving each `FFIObject` an associated `AtomicLong` counter to track
807
+ // the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy`
808
+ // has been called. These are updated according to the following rules:
809
+ //
810
+ // * The initial value of the counter is 1, indicating a live object with no in-flight calls.
811
+ // The initial value for the flag is false.
812
+ //
813
+ // * At the start of each method call, we atomically check the counter.
814
+ // If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted.
815
+ // If it is nonzero them we atomically increment it by 1 and proceed with the method call.
816
+ //
817
+ // * At the end of each method call, we atomically decrement and check the counter.
818
+ // If it has reached zero then we destroy the underlying Rust struct.
819
+ //
820
+ // * When `destroy` is called, we atomically flip the flag from false to true.
821
+ // If the flag was already true we silently fail.
822
+ // Otherwise we atomically decrement and check the counter.
823
+ // If it has reached zero then we destroy the underlying Rust struct.
824
+ //
825
+ // Astute readers may observe that this all sounds very similar to the way that Rust's `Arc<T>` works,
826
+ // and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`.
827
+ //
828
+ // The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been
829
+ // called *and* all in-flight method calls have completed, avoiding violating any of the expectations
830
+ // of the underlying Rust code.
831
+ //
832
+ // In the future we may be able to replace some of this with automatic finalization logic, such as using
833
+ // the new "Cleaner" functionaility in Java 9. The above scheme has been designed to work even if `destroy` is
834
+ // invoked by garbage-collection machinery rather than by calling code (which by the way, it's apparently also
835
+ // possible for the JVM to finalize an object while there is an in-flight call to one of its methods [1],
836
+ // so there would still be some complexity here).
837
+ //
838
+ // Sigh...all of this for want of a robust finalization mechanism.
839
+ //
840
+ // [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219
841
+ //
842
+ abstract class FFIObject(
843
+ protected val pointer: Pointer
844
+ ): Disposable, AutoCloseable {
845
+
846
+ private val wasDestroyed = AtomicBoolean(false)
847
+ private val callCounter = AtomicLong(1)
848
+
849
+ open protected fun freeRustArcPtr() {
850
+ // To be overridden in subclasses.
851
+ }
852
+
853
+ override fun destroy() {
854
+ // Only allow a single call to this method.
855
+ // TODO: maybe we should log a warning if called more than once?
856
+ if (this.wasDestroyed.compareAndSet(false, true)) {
857
+ // This decrement always matches the initial count of 1 given at creation time.
858
+ if (this.callCounter.decrementAndGet() == 0L) {
859
+ this.freeRustArcPtr()
860
+ }
861
+ }
862
+ }
863
+
864
+ @Synchronized
865
+ override fun close() {
866
+ this.destroy()
867
+ }
868
+
869
+ internal inline fun <R> callWithPointer(block: (ptr: Pointer) -> R): R {
870
+ // Check and increment the call counter, to keep the object alive.
871
+ // This needs a compare-and-set retry loop in case of concurrent updates.
872
+ do {
873
+ val c = this.callCounter.get()
874
+ if (c == 0L) {
875
+ throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed")
876
+ }
877
+ if (c == Long.MAX_VALUE) {
878
+ throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow")
879
+ }
880
+ } while (! this.callCounter.compareAndSet(c, c + 1L))
881
+ // Now we can safely do the method call without the pointer being freed concurrently.
882
+ try {
883
+ return block(this.pointer)
884
+ } finally {
885
+ // This decrement always matches the increment we performed above.
886
+ if (this.callCounter.decrementAndGet() == 0L) {
887
+ this.freeRustArcPtr()
888
+ }
889
+ }
890
+ }
891
+ }
892
+
893
+ public interface EventNotifierInterface {
894
+
895
+ companion object
896
+ }
897
+
898
+ class EventNotifier(
899
+ pointer: Pointer
900
+ ) : FFIObject(pointer), EventNotifierInterface {
901
+
902
+ /**
903
+ * Disconnect the object from the underlying Rust object.
904
+ *
905
+ * It can be called more than once, but once called, interacting with the object
906
+ * causes an `IllegalStateException`.
907
+ *
908
+ * Clients **must** call this method once done with the object, or cause a memory leak.
909
+ */
910
+ override protected fun freeRustArcPtr() {
911
+ rustCall() { status ->
912
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_free_eventnotifier(this.pointer, status)
913
+ }
914
+ }
915
+
916
+
917
+
918
+
919
+ companion object
920
+
921
+ }
922
+
923
+ public object FfiConverterTypeEventNotifier: FfiConverter<EventNotifier, Pointer> {
924
+ override fun lower(value: EventNotifier): Pointer = value.callWithPointer { it }
925
+
926
+ override fun lift(value: Pointer): EventNotifier {
927
+ return EventNotifier(value)
928
+ }
929
+
930
+ override fun read(buf: ByteBuffer): EventNotifier {
931
+ // The Rust code always writes pointers as 8 bytes, and will
932
+ // fail to compile if they don't fit.
933
+ return lift(Pointer(buf.getLong()))
934
+ }
935
+
936
+ override fun allocationSize(value: EventNotifier) = 8
937
+
938
+ override fun write(value: EventNotifier, buf: ByteBuffer) {
939
+ // The Rust code always expects pointers written as 8 bytes,
940
+ // and will fail to compile if they don't fit.
941
+ buf.putLong(Pointer.nativeValue(lower(value)))
942
+ }
943
+ }
944
+
945
+
946
+
947
+
948
+ internal typealias Handle = Long
949
+ internal class ConcurrentHandleMap<T>(
950
+ private val leftMap: MutableMap<Handle, T> = mutableMapOf(),
951
+ private val rightMap: MutableMap<T, Handle> = mutableMapOf()
952
+ ) {
953
+ private val lock = java.util.concurrent.locks.ReentrantLock()
954
+ private val currentHandle = AtomicLong(0L)
955
+ private val stride = 1L
956
+
957
+ fun insert(obj: T): Handle =
958
+ lock.withLock {
959
+ rightMap[obj] ?:
960
+ currentHandle.getAndAdd(stride)
961
+ .also { handle ->
962
+ leftMap[handle] = obj
963
+ rightMap[obj] = handle
964
+ }
965
+ }
966
+
967
+ fun get(handle: Handle) = lock.withLock {
968
+ leftMap[handle]
969
+ }
970
+
971
+ fun delete(handle: Handle) {
972
+ this.remove(handle)
973
+ }
974
+
975
+ fun remove(handle: Handle): T? =
976
+ lock.withLock {
977
+ leftMap.remove(handle)?.let { obj ->
978
+ rightMap.remove(obj)
979
+ obj
980
+ }
981
+ }
982
+ }
983
+
984
+ interface ForeignCallback : com.sun.jna.Callback {
985
+ public fun callback(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int
986
+ }
987
+
988
+ // Magic number for the Rust proxy to call using the same mechanism as every other method,
989
+ // to free the callback once it's dropped by Rust.
990
+ internal const val IDX_CALLBACK_FREE = 0
991
+ // Callback return codes
992
+ internal const val UNIFFI_CALLBACK_SUCCESS = 0
993
+ internal const val UNIFFI_CALLBACK_ERROR = 1
994
+ internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2
995
+
996
+ public abstract class FfiConverterCallbackInterface<CallbackInterface>(
997
+ protected val foreignCallback: ForeignCallback
998
+ ): FfiConverter<CallbackInterface, Handle> {
999
+ private val handleMap = ConcurrentHandleMap<CallbackInterface>()
1000
+
1001
+ // Registers the foreign callback with the Rust side.
1002
+ // This method is generated for each callback interface.
1003
+ internal abstract fun register(lib: _UniFFILib)
1004
+
1005
+ fun drop(handle: Handle): RustBuffer.ByValue {
1006
+ return handleMap.remove(handle).let { RustBuffer.ByValue() }
1007
+ }
1008
+
1009
+ override fun lift(value: Handle): CallbackInterface {
1010
+ return handleMap.get(value) ?: throw InternalException("No callback in handlemap; this is a Uniffi bug")
1011
+ }
1012
+
1013
+ override fun read(buf: ByteBuffer) = lift(buf.getLong())
1014
+
1015
+ override fun lower(value: CallbackInterface) =
1016
+ handleMap.insert(value).also {
1017
+ assert(handleMap.get(it) === value) { "Handle map is not returning the object we just placed there. This is a bug in the HandleMap." }
1018
+ }
1019
+
1020
+ override fun allocationSize(value: CallbackInterface) = 8
1021
+
1022
+ override fun write(value: CallbackInterface, buf: ByteBuffer) {
1023
+ buf.putLong(lower(value))
1024
+ }
1025
+ }
1026
+
1027
+ // Declaration and FfiConverters for EventListener Callback Interface
1028
+
1029
+ public interface EventListener {
1030
+ fun `onEventOccurred`(`eventData`: String)
1031
+
1032
+ companion object
1033
+ }
1034
+
1035
+ // The ForeignCallback that is passed to Rust.
1036
+ internal class ForeignCallbackTypeEventListener : ForeignCallback {
1037
+ @Suppress("TooGenericExceptionCaught")
1038
+ override fun callback(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int {
1039
+ val cb = FfiConverterTypeEventListener.lift(handle)
1040
+ return when (method) {
1041
+ IDX_CALLBACK_FREE -> {
1042
+ FfiConverterTypeEventListener.drop(handle)
1043
+ // Successful return
1044
+ // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs`
1045
+ UNIFFI_CALLBACK_SUCCESS
1046
+ }
1047
+ 1 -> {
1048
+ // Call the method, write to outBuf and return a status code
1049
+ // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info
1050
+ try {
1051
+ this.`invokeOnEventOccurred`(cb, argsData, argsLen, outBuf)
1052
+ } catch (e: Throwable) {
1053
+ // Unexpected error
1054
+ try {
1055
+ // Try to serialize the error into a string
1056
+ outBuf.setValue(FfiConverterString.lower(e.toString()))
1057
+ } catch (e: Throwable) {
1058
+ // If that fails, then it's time to give up and just return
1059
+ }
1060
+ UNIFFI_CALLBACK_UNEXPECTED_ERROR
1061
+ }
1062
+ }
1063
+
1064
+ else -> {
1065
+ // An unexpected error happened.
1066
+ // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs`
1067
+ try {
1068
+ // Try to serialize the error into a string
1069
+ outBuf.setValue(FfiConverterString.lower("Invalid Callback index"))
1070
+ } catch (e: Throwable) {
1071
+ // If that fails, then it's time to give up and just return
1072
+ }
1073
+ UNIFFI_CALLBACK_UNEXPECTED_ERROR
1074
+ }
1075
+ }
1076
+ }
1077
+
1078
+
1079
+ @Suppress("UNUSED_PARAMETER")
1080
+ private fun `invokeOnEventOccurred`(kotlinCallbackInterface: EventListener, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int {
1081
+ val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also {
1082
+ it.order(ByteOrder.BIG_ENDIAN)
1083
+ }
1084
+ fun makeCall() : Int {
1085
+ kotlinCallbackInterface.`onEventOccurred`(
1086
+ FfiConverterString.read(argsBuf)
1087
+ )
1088
+ return UNIFFI_CALLBACK_SUCCESS
1089
+ }
1090
+ fun makeCallAndHandleError() : Int = makeCall()
1091
+
1092
+ return makeCallAndHandleError()
1093
+ }
1094
+
1095
+ }
1096
+
1097
+ // The ffiConverter which transforms the Callbacks in to Handles to pass to Rust.
1098
+ public object FfiConverterTypeEventListener: FfiConverterCallbackInterface<EventListener>(
1099
+ foreignCallback = ForeignCallbackTypeEventListener()
1100
+ ) {
1101
+ override fun register(lib: _UniFFILib) {
1102
+ rustCall() { status ->
1103
+ lib.uniffi_pubkymobile_fn_init_callback_eventlistener(this.foreignCallback, status)
1104
+ }
1105
+ }
1106
+ }
1107
+
1108
+
709
1109
 
710
1110
 
711
1111
  public object FfiConverterSequenceString: FfiConverterRustBuffer<List<String>> {
@@ -730,32 +1130,62 @@ public object FfiConverterSequenceString: FfiConverterRustBuffer<List<String>> {
730
1130
  }
731
1131
  }
732
1132
 
1133
+ fun `auth`(`url`: String, `secretKey`: String): List<String> {
1134
+ return FfiConverterSequenceString.lift(
1135
+ rustCall() { _status ->
1136
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_auth(FfiConverterString.lower(`url`),FfiConverterString.lower(`secretKey`),_status)
1137
+ })
1138
+ }
1139
+
733
1140
 
1141
+ fun `createRecoveryFile`(`secretKey`: String, `passphrase`: String): List<String> {
1142
+ return FfiConverterSequenceString.lift(
1143
+ rustCall() { _status ->
1144
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_create_recovery_file(FfiConverterString.lower(`secretKey`),FfiConverterString.lower(`passphrase`),_status)
1145
+ })
1146
+ }
734
1147
 
735
1148
 
1149
+ fun `decryptRecoveryFile`(`recoveryFile`: String, `passphrase`: String): List<String> {
1150
+ return FfiConverterSequenceString.lift(
1151
+ rustCall() { _status ->
1152
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_decrypt_recovery_file(FfiConverterString.lower(`recoveryFile`),FfiConverterString.lower(`passphrase`),_status)
1153
+ })
1154
+ }
736
1155
 
737
- fun `auth`(`url`: String, `secretKey`: String): List<String> {
1156
+
1157
+ fun `deleteFile`(`url`: String): List<String> {
738
1158
  return FfiConverterSequenceString.lift(
739
1159
  rustCall() { _status ->
740
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_auth(FfiConverterString.lower(`url`),FfiConverterString.lower(`secretKey`),_status)
1160
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_delete_file(FfiConverterString.lower(`url`),_status)
741
1161
  })
742
1162
  }
743
1163
 
744
1164
 
745
- @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
746
- suspend fun `get`(`url`: String) : List<String> {
747
- return uniffiRustCallAsync(
748
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_get(FfiConverterString.lower(`url`),),
749
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_poll_rust_buffer(future, continuation) },
750
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_complete_rust_buffer(future, continuation) },
751
- { future -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_free_rust_buffer(future) },
752
- // lift function
753
- { FfiConverterSequenceString.lift(it) },
754
- // Error FFI converter
755
- NullCallStatusErrorHandler,
756
- )
1165
+ fun `generateSecretKey`(): List<String> {
1166
+ return FfiConverterSequenceString.lift(
1167
+ rustCall() { _status ->
1168
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_generate_secret_key(_status)
1169
+ })
757
1170
  }
758
1171
 
1172
+
1173
+ fun `get`(`url`: String): List<String> {
1174
+ return FfiConverterSequenceString.lift(
1175
+ rustCall() { _status ->
1176
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_get(FfiConverterString.lower(`url`),_status)
1177
+ })
1178
+ }
1179
+
1180
+
1181
+ fun `getPublicKeyFromSecretKey`(`secretKey`: String): List<String> {
1182
+ return FfiConverterSequenceString.lift(
1183
+ rustCall() { _status ->
1184
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_get_public_key_from_secret_key(FfiConverterString.lower(`secretKey`),_status)
1185
+ })
1186
+ }
1187
+
1188
+
759
1189
  fun `list`(`url`: String): List<String> {
760
1190
  return FfiConverterSequenceString.lift(
761
1191
  rustCall() { _status ->
@@ -788,20 +1218,22 @@ fun `publishHttps`(`recordName`: String, `target`: String, `secretKey`: String):
788
1218
  }
789
1219
 
790
1220
 
791
- @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
792
- suspend fun `put`(`url`: String, `content`: String) : List<String> {
793
- return uniffiRustCallAsync(
794
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_put(FfiConverterString.lower(`url`),FfiConverterString.lower(`content`),),
795
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_poll_rust_buffer(future, continuation) },
796
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_complete_rust_buffer(future, continuation) },
797
- { future -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_free_rust_buffer(future) },
798
- // lift function
799
- { FfiConverterSequenceString.lift(it) },
800
- // Error FFI converter
801
- NullCallStatusErrorHandler,
802
- )
1221
+ fun `put`(`url`: String, `content`: String): List<String> {
1222
+ return FfiConverterSequenceString.lift(
1223
+ rustCall() { _status ->
1224
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_put(FfiConverterString.lower(`url`),FfiConverterString.lower(`content`),_status)
1225
+ })
1226
+ }
1227
+
1228
+
1229
+ fun `removeEventListener`() =
1230
+
1231
+ rustCall() { _status ->
1232
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_remove_event_listener(_status)
803
1233
  }
804
1234
 
1235
+
1236
+
805
1237
  fun `resolve`(`publicKey`: String): List<String> {
806
1238
  return FfiConverterSequenceString.lift(
807
1239
  rustCall() { _status ->
@@ -818,45 +1250,43 @@ fun `resolveHttps`(`publicKey`: String): List<String> {
818
1250
  }
819
1251
 
820
1252
 
821
- @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
822
- suspend fun `signIn`(`secretKey`: String) : List<String> {
823
- return uniffiRustCallAsync(
824
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_in(FfiConverterString.lower(`secretKey`),),
825
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_poll_rust_buffer(future, continuation) },
826
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_complete_rust_buffer(future, continuation) },
827
- { future -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_free_rust_buffer(future) },
828
- // lift function
829
- { FfiConverterSequenceString.lift(it) },
830
- // Error FFI converter
831
- NullCallStatusErrorHandler,
832
- )
833
- }
834
-
835
- @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
836
- suspend fun `signOut`(`secretKey`: String) : List<String> {
837
- return uniffiRustCallAsync(
838
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_out(FfiConverterString.lower(`secretKey`),),
839
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_poll_rust_buffer(future, continuation) },
840
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_complete_rust_buffer(future, continuation) },
841
- { future -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_free_rust_buffer(future) },
842
- // lift function
843
- { FfiConverterSequenceString.lift(it) },
844
- // Error FFI converter
845
- NullCallStatusErrorHandler,
846
- )
847
- }
848
-
849
- @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
850
- suspend fun `signUp`(`secretKey`: String, `homeserver`: String) : List<String> {
851
- return uniffiRustCallAsync(
852
- _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_up(FfiConverterString.lower(`secretKey`),FfiConverterString.lower(`homeserver`),),
853
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_poll_rust_buffer(future, continuation) },
854
- { future, continuation -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_complete_rust_buffer(future, continuation) },
855
- { future -> _UniFFILib.INSTANCE.ffi_pubkymobile_rust_future_free_rust_buffer(future) },
856
- // lift function
857
- { FfiConverterSequenceString.lift(it) },
858
- // Error FFI converter
859
- NullCallStatusErrorHandler,
860
- )
1253
+ fun `session`(`pubky`: String): List<String> {
1254
+ return FfiConverterSequenceString.lift(
1255
+ rustCall() { _status ->
1256
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_session(FfiConverterString.lower(`pubky`),_status)
1257
+ })
861
1258
  }
862
1259
 
1260
+
1261
+ fun `setEventListener`(`listener`: EventListener) =
1262
+
1263
+ rustCall() { _status ->
1264
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_set_event_listener(FfiConverterTypeEventListener.lower(`listener`),_status)
1265
+ }
1266
+
1267
+
1268
+
1269
+ fun `signIn`(`secretKey`: String): List<String> {
1270
+ return FfiConverterSequenceString.lift(
1271
+ rustCall() { _status ->
1272
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_in(FfiConverterString.lower(`secretKey`),_status)
1273
+ })
1274
+ }
1275
+
1276
+
1277
+ fun `signOut`(`secretKey`: String): List<String> {
1278
+ return FfiConverterSequenceString.lift(
1279
+ rustCall() { _status ->
1280
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_out(FfiConverterString.lower(`secretKey`),_status)
1281
+ })
1282
+ }
1283
+
1284
+
1285
+ fun `signUp`(`secretKey`: String, `homeserver`: String): List<String> {
1286
+ return FfiConverterSequenceString.lift(
1287
+ rustCall() { _status ->
1288
+ _UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_sign_up(FfiConverterString.lower(`secretKey`),FfiConverterString.lower(`homeserver`),_status)
1289
+ })
1290
+ }
1291
+
1292
+