diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e67efac5b..80585669f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,3 +24,10 @@ jobs: with: file: docker/jvm.Dockerfile tags: toxchat/jvm-toxcore-c:jvm + + ktlint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.1.1/ktlint && chmod a+x ktlint + - run: ./ktlint diff --git a/lib/src/main/java/im/tox/tox4j/av/ToxAv.kt b/lib/src/main/java/im/tox/tox4j/av/ToxAv.kt index bcd10ed8b..1a1c5a8e1 100644 --- a/lib/src/main/java/im/tox/tox4j/av/ToxAv.kt +++ b/lib/src/main/java/im/tox/tox4j/av/ToxAv.kt @@ -29,136 +29,155 @@ import java.io.Closeable * forcibly terminated without notifying peers. */ interface ToxAv : Closeable { + /** + * Start new A/V session. There can only be only one session per Tox instance. + * + * @param tox A compatible ToxCore implementation. + * @return the new A/V session. + * @throws ToxavNewException + */ + fun create(tox: ToxCore): ToxAv - /** - * Start new A/V session. There can only be only one session per Tox instance. - * - * @param tox A compatible ToxCore implementation. - * @return the new A/V session. - */ - // @throws[ToxavNewException] - fun create(tox: ToxCore): ToxAv + /** + * Releases all resources associated with the A/V session. + * + * If any calls were ongoing, these will be forcibly terminated without notifying peers. After + * calling this function, no other functions may be called and the av pointer becomes invalid. + */ + override fun close(): Unit - /** - * Releases all resources associated with the A/V session. - * - * If any calls were ongoing, these will be forcibly terminated without notifying peers. After - * calling this function, no other functions may be called and the av pointer becomes invalid. - */ - override fun close(): Unit + /** Returns the interval in milliseconds when the next [[iterate]] call should be. */ + val iterationInterval: Int - /** Returns the interval in milliseconds when the next [[iterate]] call should be. */ - val iterationInterval: Int + /** + * Main loop for the session. This function needs to be called in intervals of + * [[iterationInterval]] milliseconds. It is best called in the separate thread from + * [[ToxCore.iterate]]. + */ + fun iterate( + handler: ToxAvEventListener, + state: S, + ): S - /** - * Main loop for the session. This function needs to be called in intervals of - * [[iterationInterval]] milliseconds. It is best called in the separate thread from - * [[ToxCore.iterate]]. - */ - fun iterate(handler: ToxAvEventListener, state: S): S + /** + * Call a friend. This will start ringing the friend. + * + * It is the client's responsibility to stop ringing after a certain timeout, if such behaviour is + * desired. If the client does not stop ringing, the library will not stop until the friend is + * disconnected. + * + * @param friendNumber The friend number of the friend that should be called. + * @param audioBitRate Audio bit rate in Kb/sec. Set this to 0 to disable audio sending. + * @param videoBitRate Video bit rate in Kb/sec. Set this to 0 to disable video sending. + * @throws ToxavCallException + */ + fun call( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + videoBitRate: BitRate, + ): Unit - /** - * Call a friend. This will start ringing the friend. - * - * It is the client's responsibility to stop ringing after a certain timeout, if such behaviour is - * desired. If the client does not stop ringing, the library will not stop until the friend is - * disconnected. - * - * @param friendNumber The friend number of the friend that should be called. - * @param audioBitRate Audio bit rate in Kb/sec. Set this to 0 to disable audio sending. - * @param videoBitRate Video bit rate in Kb/sec. Set this to 0 to disable video sending. - */ - // @throws[ToxavCallException] - fun call(friendNumber: ToxFriendNumber, audioBitRate: BitRate, videoBitRate: BitRate): Unit + /** + * Accept an incoming call. + * + * If answering fails for any reason, the call will still be pending and it is possible to try and + * answer it later. + * + * @param friendNumber The friend number of the friend that is calling. + * @param audioBitRate Audio bit rate in Kb/sec. Set this to 0 to disable audio sending. + * @param videoBitRate Video bit rate in Kb/sec. Set this to 0 to disable video sending. + * @throws ToxavAnswerException + */ + fun answer( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + videoBitRate: BitRate, + ): Unit - /** - * Accept an incoming call. - * - * If answering fails for any reason, the call will still be pending and it is possible to try and - * answer it later. - * - * @param friendNumber The friend number of the friend that is calling. - * @param audioBitRate Audio bit rate in Kb/sec. Set this to 0 to disable audio sending. - * @param videoBitRate Video bit rate in Kb/sec. Set this to 0 to disable video sending. - */ - // @throws[ToxavAnswerException] - fun answer(friendNumber: ToxFriendNumber, audioBitRate: BitRate, videoBitRate: BitRate): Unit + /** + * Sends a call control command to a friend. + * + * @param friendNumber The friend number of the friend to send the call control to. + * @param control The control command to send. + * @throws ToxavCallControlException + */ + fun callControl( + friendNumber: ToxFriendNumber, + control: ToxavCallControl, + ): Unit - /** - * Sends a call control command to a friend. - * - * @param friendNumber The friend number of the friend to send the call control to. - * @param control The control command to send. - */ - // @throws[ToxavCallControlException] - fun callControl(friendNumber: ToxFriendNumber, control: ToxavCallControl): Unit + /** + * Set the audio bit rate to be used in subsequent audio frames. + * + * @param friendNumber The friend number of the friend for which to set the audio bit rate. + * @param audioBitRate The new audio bit rate in Kb/sec. Set to 0 to disable audio sending. Pass + * -1 to leave unchanged. + * @throws ToxavBitRateSetException + */ + fun setAudioBitRate( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + ): Unit - /** - * Set the audio bit rate to be used in subsequent audio frames. - * - * @param friendNumber The friend number of the friend for which to set the audio bit rate. - * @param audioBitRate The new audio bit rate in Kb/sec. Set to 0 to disable audio sending. Pass - * -1 to leave unchanged. - */ - // @throws[ToxavBitRateSetException] - fun setAudioBitRate(friendNumber: ToxFriendNumber, audioBitRate: BitRate): Unit + /** + * Set the video bit rate to be used in subsequent audio frames. + * + * @param friendNumber The friend number of the friend for which to set the audio bit rate. + * @param videoBitRate The new video bit rate in Kb/sec. Set to 0 to disable video sending. Pass + * -1 to leave unchanged. + * @throws ToxavBitRateSetException + */ + fun setVideoBitRate( + friendNumber: ToxFriendNumber, + videoBitRate: BitRate, + ): Unit - /** - * Set the video bit rate to be used in subsequent audio frames. - * - * @param friendNumber The friend number of the friend for which to set the audio bit rate. - * @param videoBitRate The new video bit rate in Kb/sec. Set to 0 to disable video sending. Pass - * -1 to leave unchanged. - */ - // @throws[ToxavBitRateSetException] - fun setVideoBitRate(friendNumber: ToxFriendNumber, videoBitRate: BitRate): Unit + /** + * Send an audio frame to a friend. + * + * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]... Meaning: sample 1 + * for channel 1, sample 1 for channel 2, ... For mono audio, this has no meaning, every sample is + * subsequent. For stereo, this means the expected format is LRLRLR... with samples for left and + * right alternating. + * + * @param friendNumber The friend number of the friend to which to send an audio frame. + * @param pcm An array of audio samples. The size of this array must be sample_count * channels. + * @param sampleCount Number of samples in this frame in milliseconds. Valid numbers here are + * ((sample rate) * (audio length) / 1000), where audio length can be 2.5, 5, 10, 20, 40 or 60 + * milliseconds. + * @param channels Number of audio channels. Supported values are 1 and 2. + * @param samplingRate Audio sampling rate used in this frame in Hz. Valid sampling rates are + * 8000, 12000, 16000, 24000, or 48000. + * @throws ToxavSendFrameException + */ + fun audioSendFrame( + friendNumber: ToxFriendNumber, + pcm: ShortArray, + sampleCount: SampleCount, + channels: AudioChannels, + samplingRate: SamplingRate, + ): Unit - /** - * Send an audio frame to a friend. - * - * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]... Meaning: sample 1 - * for channel 1, sample 1 for channel 2, ... For mono audio, this has no meaning, every sample is - * subsequent. For stereo, this means the expected format is LRLRLR... with samples for left and - * right alternating. - * - * @param friendNumber The friend number of the friend to which to send an audio frame. - * @param pcm An array of audio samples. The size of this array must be sample_count * channels. - * @param sampleCount Number of samples in this frame in milliseconds. Valid numbers here are - * ((sample rate) * (audio length) / 1000), where audio length can be 2.5, 5, 10, 20, 40 or 60 - * milliseconds. - * @param channels Number of audio channels. Supported values are 1 and 2. - * @param samplingRate Audio sampling rate used in this frame in Hz. Valid sampling rates are - * 8000, 12000, 16000, 24000, or 48000. - */ - // @throws[ToxavSendFrameException] - fun audioSendFrame( - friendNumber: ToxFriendNumber, - pcm: ShortArray, - sampleCount: SampleCount, - channels: AudioChannels, - samplingRate: SamplingRate - ): Unit - - /** - * Send a video frame to a friend. - * - * Y - plane should be of size: height * width U - plane should be of size: (height/2) * (width/2) - * V - plane should be of size: (height/2) * (width/2) - * - * @param friendNumber The friend number of the friend to which to send a video frame. - * @param width Width of the frame in pixels. - * @param height Height of the frame in pixels. - * @param y Y (Luminance) plane data. - * @param u U (Chroma) plane data. - * @param v V (Chroma) plane data. - */ - // @throws[ToxavSendFrameException] - fun videoSendFrame( - friendNumber: ToxFriendNumber, - width: Int, - height: Int, - y: ByteArray, - u: ByteArray, - v: ByteArray - ): Unit + /** + * Send a video frame to a friend. + * + * Y - plane should be of size: height * width U - plane should be of size: (height/2) * (width/2) + * V - plane should be of size: (height/2) * (width/2) + * + * @param friendNumber The friend number of the friend to which to send a video frame. + * @param width Width of the frame in pixels. + * @param height Height of the frame in pixels. + * @param y Y (Luminance) plane data. + * @param u U (Chroma) plane data. + * @param v V (Chroma) plane data. + * @throws ToxavSendFrameException + */ + fun videoSendFrame( + friendNumber: ToxFriendNumber, + width: Int, + height: Int, + y: ByteArray, + u: ByteArray, + v: ByteArray, + ): Unit } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioBitRateCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioBitRateCallback.kt index f6c4b95dc..e4de2e985 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioBitRateCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioBitRateCallback.kt @@ -8,13 +8,13 @@ import im.tox.tox4j.core.data.ToxFriendNumber * point core suggests new bit rates. */ interface AudioBitRateCallback { - /** - * @param friendNumber The friend number of the friend for which to set the audio bit rate. - * @param audioBitRate Suggested maximum audio bit rate in Kb/sec. - */ - fun audioBitRate( - friendNumber: ToxFriendNumber, - audioBitRate: BitRate, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend for which to set the audio bit rate. + * @param audioBitRate Suggested maximum audio bit rate in Kb/sec. + */ + fun audioBitRate( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioReceiveFrameCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioReceiveFrameCallback.kt index bcd858a39..f3cd5b2fa 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioReceiveFrameCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/AudioReceiveFrameCallback.kt @@ -6,17 +6,17 @@ import im.tox.tox4j.core.data.ToxFriendNumber /** Called when an audio frame is received. */ interface AudioReceiveFrameCallback { - /** - * @param friendNumber The friend number of the friend who sent an audio frame. - * @param pcm An array of audio samples (sample_count * channels elements). - * @param channels Number of audio channels. - * @param samplingRate Sampling rate used in this frame. - */ - fun audioReceiveFrame( - friendNumber: ToxFriendNumber, - pcm: ShortArray, - channels: AudioChannels, - samplingRate: SamplingRate, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who sent an audio frame. + * @param pcm An array of audio samples (sample_count * channels elements). + * @param channels Number of audio channels. + * @param samplingRate Sampling rate used in this frame. + */ + fun audioReceiveFrame( + friendNumber: ToxFriendNumber, + pcm: ShortArray, + channels: AudioChannels, + samplingRate: SamplingRate, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/CallCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/CallCallback.kt index 67ad040b5..ec686ae3a 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/CallCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/CallCallback.kt @@ -4,15 +4,15 @@ import im.tox.tox4j.core.data.ToxFriendNumber /** Triggered when a friend calls us. */ interface CallCallback { - /** - * @param friendNumber The friend number from which the call is incoming. - * @param audioEnabled True if friend is sending audio. - * @param videoEnabled True if friend is sending video. - */ - fun call( - friendNumber: ToxFriendNumber, - audioEnabled: Boolean, - videoEnabled: Boolean, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number from which the call is incoming. + * @param audioEnabled True if friend is sending audio. + * @param videoEnabled True if friend is sending video. + */ + fun call( + friendNumber: ToxFriendNumber, + audioEnabled: Boolean, + videoEnabled: Boolean, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/CallStateCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/CallStateCallback.kt index 047b451c8..09a747fff 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/CallStateCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/CallStateCallback.kt @@ -6,15 +6,15 @@ import java.util.EnumSet /** Called when the call state changes. */ interface CallStateCallback { - /** - * @param friendNumber The friend number this call state change is for. - * @param callState A set of ToxCallState values comprising the new call state. Although this is a - * Collection (therefore might actually be a List), this is effectively a Set. Any - * [[ToxavFriendCallState]] value is contained exactly 0 or 1 times. - */ - fun callState( - friendNumber: ToxFriendNumber, - callState: EnumSet, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number this call state change is for. + * @param callState A set of ToxCallState values comprising the new call state. Although this is a + * Collection (therefore might actually be a List), this is effectively a Set. Any + * [[ToxavFriendCallState]] value is contained exactly 0 or 1 times. + */ + fun callState( + friendNumber: ToxFriendNumber, + callState: EnumSet, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoBitRateCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoBitRateCallback.kt index 612fbb61f..240e497c0 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoBitRateCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoBitRateCallback.kt @@ -8,13 +8,13 @@ import im.tox.tox4j.core.data.ToxFriendNumber * point core suggests new bit rates. */ interface VideoBitRateCallback { - /** - * @param friendNumber The friend number of the friend for which to set the video bit rate. - * @param videoBitRate Suggested maximum video bit rate in Kb/sec. - */ - fun videoBitRate( - friendNumber: ToxFriendNumber, - videoBitRate: BitRate, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend for which to set the video bit rate. + * @param videoBitRate Suggested maximum video bit rate in Kb/sec. + */ + fun videoBitRate( + friendNumber: ToxFriendNumber, + videoBitRate: BitRate, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoReceiveFrameCallback.kt b/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoReceiveFrameCallback.kt index 800d0c58f..1009c9d44 100644 --- a/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoReceiveFrameCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/av/callbacks/VideoReceiveFrameCallback.kt @@ -6,44 +6,44 @@ import im.tox.tox4j.core.data.ToxFriendNumber /** Triggered when a video frame is received. */ interface VideoReceiveFrameCallback { - /** - * @param friendNumber The friend number of the friend who sent a video frame. - * @param width Width of the frame in pixels. - * @param height Height of the frame in pixels. - * @param y Y-plane. - * @param u U-plane. - * @param v V-plane. The size of plane data is derived from width and height where Y = max(width, - * abs(yStride)) * height U = max(width/2, abs(uStride)) * (height/2) V = max(width/2, - * abs(vStride)) * (height/2). - * @param yStride Stride length for Y-plane. - * @param uStride Stride length for U-plane. - * @param vStride Stride length for V-plane. Strides represent padding for each plane that may or - * may not be present. You must handle strides in your image processing code. Strides are - * negative if the image is bottom-up hence why you must abs() it when calculating plane buffer - * size. - */ - fun videoReceiveFrame( - friendNumber: ToxFriendNumber, - width: Width, - height: Height, - y: ByteArray, - u: ByteArray, - v: ByteArray, - yStride: Int, - uStride: Int, - vStride: Int, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who sent a video frame. + * @param width Width of the frame in pixels. + * @param height Height of the frame in pixels. + * @param y Y-plane. + * @param u U-plane. + * @param v V-plane. The size of plane data is derived from width and height where Y = max(width, + * abs(yStride)) * height U = max(width/2, abs(uStride)) * (height/2) V = max(width/2, + * abs(vStride)) * (height/2). + * @param yStride Stride length for Y-plane. + * @param uStride Stride length for U-plane. + * @param vStride Stride length for V-plane. Strides represent padding for each plane that may or + * may not be present. You must handle strides in your image processing code. Strides are + * negative if the image is bottom-up hence why you must abs() it when calculating plane buffer + * size. + */ + fun videoReceiveFrame( + friendNumber: ToxFriendNumber, + width: Width, + height: Height, + y: ByteArray, + u: ByteArray, + v: ByteArray, + yStride: Int, + uStride: Int, + vStride: Int, + state: ToxCoreState, + ): ToxCoreState = state - /** - * An implementation may choose to keep the arrays to copy the data to around as an optimisation. - * If this method does not return [[null]], the arrays in the return value are passed to - * [[videoReceiveFrame]] as y, u, and v. - */ - fun videoFrameCachedYUV( - height: Height, - yStride: Int, - uStride: Int, - vStride: Int - ): Triple? = null + /** + * An implementation may choose to keep the arrays to copy the data to around as an optimisation. + * If this method does not return [[null]], the arrays in the return value are passed to + * [[videoReceiveFrame]] as y, u, and v. + */ + fun videoFrameCachedYUV( + height: Height, + yStride: Int, + uStride: Int, + vStride: Int, + ): Triple? = null } diff --git a/lib/src/main/java/im/tox/tox4j/av/data/AudioChannels.kt b/lib/src/main/java/im/tox/tox4j/av/data/AudioChannels.kt index 3984a89b9..70c745560 100644 --- a/lib/src/main/java/im/tox/tox4j/av/data/AudioChannels.kt +++ b/lib/src/main/java/im/tox/tox4j/av/data/AudioChannels.kt @@ -1,6 +1,6 @@ package im.tox.tox4j.av.data enum class AudioChannels(val value: Int) { - Mono(1), - Stereo(2), + Mono(1), + Stereo(2), } diff --git a/lib/src/main/java/im/tox/tox4j/av/data/AudioLength.kt b/lib/src/main/java/im/tox/tox4j/av/data/AudioLength.kt index a8f63c2ac..7ab6f457e 100644 --- a/lib/src/main/java/im/tox/tox4j/av/data/AudioLength.kt +++ b/lib/src/main/java/im/tox/tox4j/av/data/AudioLength.kt @@ -1,13 +1,15 @@ package im.tox.tox4j.av.data /** Length in microseconds. */ +@Suppress("ktlint:standard:enum-entry-name-case") enum class AudioLength(val value: Int) { - Length2_5(2500), - Length5(5000), - Length10(10000), - Length20(20000), - Length40(40000), - Length60(60000); + Length2_5(2500), + Length5(5000), + Length10(10000), + Length20(20000), + Length40(40000), + Length60(60000), + ; - fun toMillis(): Double = value * 0.001 + fun toMillis(): Double = value * 0.001 } diff --git a/lib/src/main/java/im/tox/tox4j/av/data/BitRate.kt b/lib/src/main/java/im/tox/tox4j/av/data/BitRate.kt index c021d6d99..a78f31d09 100644 --- a/lib/src/main/java/im/tox/tox4j/av/data/BitRate.kt +++ b/lib/src/main/java/im/tox/tox4j/av/data/BitRate.kt @@ -2,8 +2,8 @@ package im.tox.tox4j.av.data @JvmInline value class BitRate(val value: Int) { - companion object { - val Unchanged: BitRate = BitRate(-1) - val Disabled: BitRate = BitRate(0) - } + companion object { + val Unchanged: BitRate = BitRate(-1) + val Disabled: BitRate = BitRate(0) + } } diff --git a/lib/src/main/java/im/tox/tox4j/av/data/SampleCount.kt b/lib/src/main/java/im/tox/tox4j/av/data/SampleCount.kt index c05fff8ce..8c92801f8 100644 --- a/lib/src/main/java/im/tox/tox4j/av/data/SampleCount.kt +++ b/lib/src/main/java/im/tox/tox4j/av/data/SampleCount.kt @@ -2,8 +2,8 @@ package im.tox.tox4j.av.data @JvmInline value class SampleCount(val value: Int) { - constructor( - audioLength: AudioLength, - samplingRate: SamplingRate - ) : this((samplingRate.value / 1000 * audioLength.toMillis()).toInt()) + constructor( + audioLength: AudioLength, + samplingRate: SamplingRate, + ) : this((samplingRate.value / 1000 * audioLength.toMillis()).toInt()) } diff --git a/lib/src/main/java/im/tox/tox4j/av/data/SamplingRate.kt b/lib/src/main/java/im/tox/tox4j/av/data/SamplingRate.kt index 4dab96e26..98dc5ef49 100644 --- a/lib/src/main/java/im/tox/tox4j/av/data/SamplingRate.kt +++ b/lib/src/main/java/im/tox/tox4j/av/data/SamplingRate.kt @@ -1,9 +1,9 @@ package im.tox.tox4j.av.data enum class SamplingRate(val value: Int) { - Rate8k(8000), - Rate12k(12000), - Rate16k(16000), - Rate24k(24000), - Rate48k(48000), + Rate8k(8000), + Rate12k(12000), + Rate16k(16000), + Rate24k(24000), + Rate48k(48000), } diff --git a/lib/src/main/java/im/tox/tox4j/core/ToxCore.kt b/lib/src/main/java/im/tox/tox4j/core/ToxCore.kt index e0a5b9e88..b0ddb61aa 100644 --- a/lib/src/main/java/im/tox/tox4j/core/ToxCore.kt +++ b/lib/src/main/java/im/tox/tox4j/core/ToxCore.kt @@ -32,531 +32,566 @@ import java.io.Closeable * should be installed in all threads. */ interface ToxCore : Closeable { - - /** - * Store all information associated with the tox instance to a byte array. - * - * The data in the byte array can be used to create a new instance with [[load]] by passing it to - * the [[ToxOptions]] constructor. The concrete format in this serialised instance is - * implementation-defined. Passing save data created by one class to a different class may not - * work. - * - * @return a byte array containing the serialised tox instance. - */ - val getSavedata: ByteArray - - /** - * Create a new [[ToxCore]] instance with different options. The implementation may choose to - * create an object of its own class or a different class. If the implementation was compatible - * with another subsystem implementation (e.g. [[im.tox.tox4j.av.ToxAv]]), then the new object - * must be compatible with the same implementation. - * - * This function will bring the instance into a valid state. Running the event loop with a new - * instance will operate correctly. - * - * If the [[ToxOptions.saveData]] field is not empty, this function will load the Tox instance - * from a byte array previously filled by [[getSavedata]]. - * - * If loading failed or succeeded only partially, an exception will be thrown. - * - * @return a new [[ToxCore]] instance. - */ - // @Throws(ToxNewException::class) - fun load(options: ToxOptions): ToxCore - - /** - * Shut down the tox instance. - * - * Releases all resources associated with the Tox instance and disconnects from the network. - * - * Once this method has been called, all other calls on this instance will throw - * [ [im.tox.tox4j.exceptions.ToxKilledException]]. A closed instance cannot be reused; a new - * instance must be created. - */ - override fun close(): Unit - - /** - * Bootstrap into the tox network. - * - * Sends a "get nodes" request to the given bootstrap node with IP, port, and public key to setup - * connections. - * - * This function will only attempt to connect to the node using UDP. If you want to additionally - * attempt to connect using TCP, use [[addTcpRelay]] together with this function. - * - * @param address the hostname, or an IPv4/IPv6 address of the node. - * @param port the port of the node. - * @param publicKey the public key of the node. - */ - // @Throws(ToxBootstrapException::class) - fun bootstrap(address: String, port: Port, publicKey: ToxPublicKey): Unit - - /** - * Connect to a TCP relay to forward traffic. - * - * This function can be used to initiate TCP connections to different ports on the same bootstrap - * node, or to add TCP relays without using them as bootstrap nodes. - * - * @param address the hostname, or an IPv4/IPv6 address of the node. - * @param port the TCP port the node is running a relay on. - * @param publicKey the public key of the node. - */ - // @Throws(ToxBootstrapException::class) - fun addTcpRelay(address: String, port: Port, publicKey: ToxPublicKey): Unit - - /** - * Get the UDP port this instance is bound to. - * - * @return a port number between 1 and 65535. - */ - // @Throws(ToxGetPortException::class) - val getUdpPort: Port - - /** - * Return the TCP port this Tox instance is bound to. This is only relevant if the instance is - * acting as a TCP relay. - * - * @return a port number between 1 and 65535. - */ - // @Throws(ToxGetPortException::class) - val getTcpPort: Port - - /** - * Writes the temporary DHT public key of this instance to a byte array. - * - * This can be used in combination with an externally accessible IP address and the bound port - * (from [[getUdpPort]]}) to run a temporary bootstrap node. - * - * Be aware that every time a new instance is created, the DHT public key changes, meaning this - * cannot be used to run a permanent bootstrap node. - * - * @return a byte array of size [[ToxCoreConstants.PublicKeySize]] - */ - val getDhtId: ToxPublicKey - - /** - * Get the time in milliseconds until [[iterate]] should be called again for optimal performance. - * - * @return the time in milliseconds until [[iterate]] should be called again. - */ - val iterationInterval: Int - - /** - * The main loop. - * - * This should be invoked every [[iterationInterval]] milliseconds. - */ - fun iterate(handler: ToxCoreEventListener, state: S): S - - /** - * Copy the Tox Public Key (long term) from the Tox object. - * - * @return a byte array of size [[ToxCoreConstants.PublicKeySize]] - */ - val getPublicKey: ToxPublicKey - - /** - * Copy the Tox Secret Key from the Tox object. - * - * @return a byte array of size [[ToxCoreConstants.SecretKeySize]] - */ - val getSecretKey: ToxSecretKey - - /** - * Set the 4-byte nospam part of the address. - * - * Setting the nospam makes it impossible for others to send us friend requests that contained the - * old nospam number. - * - * @param nospam the new nospam number. - */ - fun setNospam(nospam: Int): Unit - - /** Get our current nospam number. */ - val getNospam: Int - - /** - * Get our current tox address to give to friends. - * - * The format is the following: [Public Key (32 bytes)][noSpam number (4 bytes)][checksum (2 - * bytes)]. After a call to [[setNospam]], the old address can no longer be used to send friend - * requests to this instance. - * - * Note that it is not in a human-readable format. To display it to users, it needs to be - * formatted. - * - * @return a byte array of size [[ToxCoreConstants.AddressSize]] - */ - val getAddress: ToxFriendAddress - - /** - * Set the nickname for the Tox client. - * - * Cannot be longer than [[ToxCoreConstants.MaxNameLength]] bytes. Can be empty (zero-length). - * - * @param name A byte array containing the new nickname.. - */ - // @Throws(ToxSetInfoException::class) - fun setName(name: ToxNickname): Unit - - /** Get our own nickname. */ - val getName: ToxNickname - - /** - * Set our status message. - * - * Cannot be longer than [[ToxCoreConstants.MaxStatusMessageLength]] bytes. - * - * @param message the status message to set. - */ - // @Throws(ToxSetInfoException::class) - fun setStatusMessage(message: ToxStatusMessage): Unit - - /** Gets our own status message. May be null if the status message was empty. */ - val getStatusMessage: ToxStatusMessage - - /** - * Set our status. - * - * @param status status to set. - */ - fun setStatus(status: ToxUserStatus): Unit - - /** Get our status. */ - val getStatus: ToxUserStatus - - /** - * Add a friend to the friend list and send a friend request. - * - * A friend request message must be at least 1 byte long and at most - * [ [ToxCoreConstants.MaxFriendRequestLength]]. - * - * Friend numbers are unique identifiers used in all functions that operate on friends. Once - * added, a friend number is stable for the lifetime of the Tox object. After saving the state and - * reloading it, the friend numbers may not be the same as before. Deleting a friend creates a gap - * in the friend number set, which is filled by the next adding of a friend. Any pattern in friend - * numbers should not be relied on. - * - * If more than [[Int.MaxValue]] friends are added, this function throws an exception. - * - * @param address the address to add as a friend ([[ToxCoreConstants.AddressSize]] bytes). - * - * ``` - * This is the byte array the friend got from their own [[getAddress]]. - * @param message - * ``` - * - * the message to send with the friend request (must not be empty). - * - * @return the new friend's friend number. - */ - // @Throws(ToxFriendAddException::class, IllegalArgumentException::class) - fun addFriend(address: ToxFriendAddress, message: ToxFriendRequestMessage): ToxFriendNumber - - /** - * Add a friend without sending a friend request. - * - * This function is used to add a friend in response to a friend request. If the client receives a - * friend request, it can be reasonably sure that the other client added this client as a friend, - * eliminating the need for a friend request. - * - * This function is also useful in a situation where both instances are controlled by the same - * entity, so that this entity can perform the mutual friend adding. In this case, there is no - * need for a friend request, either. - * - * @param publicKey the Public Key to add as a friend ([[ToxCoreConstants.PublicKeySize]] bytes). - * @return the new friend's friend number. - */ - // @Throws(ToxFriendAddException::class, IllegalArgumentException::class) - fun addFriendNorequest(publicKey: ToxPublicKey): ToxFriendNumber - - /** - * Remove a friend from the friend list. - * - * This does not notify the friend of their deletion. After calling this function, this client - * will appear offline to the friend and no communication can occur between the two. - * - * @param friendNumber the friend number to delete. - */ - // @Throws(ToxFriendDeleteException::class) - fun deleteFriend(friendNumber: ToxFriendNumber): Unit - - /** - * Gets the friend number for the specified Public Key. - * - * @param publicKey the Public Key. - * @return the friend number that is associated with the Public Key. - */ - // @Throws(ToxFriendByPublicKeyException::class) - fun friendByPublicKey(publicKey: ToxPublicKey): ToxFriendNumber - - /** - * Gets the Public Key for the specified friend number. - * - * @param friendNumber the friend number. - * @return the Public Key associated with the friend number. - */ - // @Throws(ToxFriendGetPublicKeyException::class) - fun getFriendPublicKey(friendNumber: ToxFriendNumber): ToxPublicKey - - /** - * Checks whether a friend with the specified friend number exists. - * - * If this function returns true, the return value is valid until the friend is - * deleted. If false is returned, the return value is valid until either of - * [ [addFriend]] or [[addFriendNorequest]] is invoked. - * - * @param friendNumber the friend number to check. - * @return true if such a friend exists. - */ - fun friendExists(friendNumber: ToxFriendNumber): Boolean - - /** - * Get an array of currently valid friend numbers. - * - * This list is valid until either of the following is invoked: [[deleteFriend]], [[addFriend]], - * [ [addFriendNorequest]]. - * - * @return an array containing the currently valid friend numbers, the empty int array if there - * are no friends. - */ - val getFriendList: IntArray - - /** - * Get an array of [[ToxFriendNumber]] objects with the same values as [[getFriendList]]. - * - * This method exists for Java compatibility, because [[getFriendList]] must return an int array. - * - * @return [[getFriendList]] mapped to [[ToxFriendNumber]]. - */ - val getFriendNumbers: List - get() = getFriendList.map { ToxFriendNumber(it) } - - /** - * Tell friend number whether or not we are currently typing. - * - * The client is responsible for turning it on or off. - * - * @param friendNumber the friend number to set typing status for. - * @param typing true if we are currently typing. - */ - // @Throws(ToxSetTypingException::class) - fun setTyping(friendNumber: ToxFriendNumber, typing: Boolean): Unit - - /** - * Send a text chat message to an online friend. - * - * This function creates a chat message packet and pushes it into the send queue. - * - * The message length may not exceed [[ToxCoreConstants.MaxMessageLength]]. Larger messages must - * be split by the client and sent as separate messages. Other clients can then reassemble the - * fragments. Messages may not be empty. - * - * The return value of this function is the message ID. If a read receipt is received, the - * triggered [[FriendReadReceiptCallback]] event will be passed this message ID. - * - * Message IDs are unique per friend per instance. The first message ID is 0. Message IDs are - * incremented by 1 each time a message is sent. If [[Int.MaxValue]] messages were sent, the next - * message ID is [[Int.MinValue]]. - * - * Message IDs are not stored in the array returned by [[getSavedata]]. - * - * @param friendNumber The friend number of the friend to send the message to. - * @param messageType Message type (normal, action, ...). - * @param timeDelta The time between composition (user created the message) and calling this - * function. - * @param message The message text - * @return the message ID. - */ - // @Throws(ToxFriendSendMessageException::class) - fun friendSendMessage( - friendNumber: ToxFriendNumber, - messageType: ToxMessageType, - timeDelta: Int, - message: ToxFriendMessage - ): Int - - /** - * Sends a file control command to a friend for a given file transfer. - * - * @param friendNumber The friend number of the friend the file is being transferred to or - * received from. - * @param fileNumber The friend-specific identifier for the file transfer. - * @param control The control command to send. - */ - // @Throws(ToxFileControlException::class) - fun fileControl(friendNumber: ToxFriendNumber, fileNumber: Int, control: ToxFileControl): Unit - - /** - * Sends a file seek control command to a friend for a given file transfer. - * - * This function can only be called to resume a file transfer right before - * [ [ToxFileControl.RESUME]] is sent. - * - * @param friendNumber The friend number of the friend the file is being received from. - * @param fileNumber The friend-specific identifier for the file transfer. - * @param position The position that the file should be seeked to. - */ - // @Throws(ToxFileSeekException::class) - fun fileSeek(friendNumber: ToxFriendNumber, fileNumber: Int, position: Long): Unit - - /** - * Return the file id associated to the file transfer as a byte array. - * - * @param friendNumber The friend number of the friend the file is being transferred to or - * received from. - * @param fileNumber The friend-specific identifier for the file transfer. - */ - // @Throws(ToxFileGetException::class) - fun getFileFileId(friendNumber: ToxFriendNumber, fileNumber: Int): ToxFileId - - /** - * Send a file transmission request. - * - * Maximum filename length is [[ToxCoreConstants.MaxFilenameLength]] bytes. The filename should - * generally just be a file name, not a path with directory names. - * - * If a non-negative file size is provided, it can be used by both sides to determine the sending - * progress. File size can be set to a negative value for streaming data of unknown size. - * - * File transmission occurs in chunks, which are requested through the [[FileChunkRequestCallback] - * ] event. - * - * When a friend goes offline, all file transfers associated with the friend are purged from core. - * - * If the file contents change during a transfer, the behaviour is unspecified in general. What - * will actually happen depends on the mode in which the file was modified and how the client - * determines the file size. - * - If the file size was increased - * - and sending mode was streaming (fileSize = -1), the behaviour - * - * ``` - * will be as expected. - * ``` - * - and sending mode was file (fileSize != -1), the - * - * ``` - * [[FileChunkRequestCallback]] callback will receive length = 0 when Core thinks - * the file transfer has finished. If the client remembers the file size as - * it was when sending the request, it will terminate the transfer normally. - * If the client re-reads the size, it will think the friend cancelled the - * transfer. - * ``` - * - If the file size was decreased - * - and sending mode was streaming, the behaviour is as expected. - * - and sending mode was file, the callback will return 0 at the new - * - * ``` - * (earlier) end-of-file, signalling to the friend that the transfer was - * cancelled. - * ``` - * - If the file contents were modified - * - at a position before the current read, the two files (local and remote) - * - * ``` - * will differ after the transfer terminates. - * ``` - * - at a position after the current read, the file transfer will succeed as - * - * ``` - * expected. - * ``` - * - In either case, both sides will regard the transfer as complete and - * - * ``` - * successful. - * - * @param friendNumber - * ``` - * - * The friend number of the friend the file send request should be sent to. - * - * @param kind The meaning of the file to be sent. - * @param fileSize Size in bytes of the file the client wants to send, -1 if unknown or streaming. - * @param fileId A file identifier of length [[ToxCoreConstants.FileIdLength]] that can be used to - * - * ``` - * uniquely identify file transfers across core restarts. If empty, a random one will - * be generated by core. It can then be obtained by using [[getFileFileId]] - * @param filename - * ``` - * - * Name of the file. Does not need to be the actual name. This - * - * ``` - * name will be sent along with the file send request. - * @return - * ``` - * - * A file number used as an identifier in subsequent callbacks. This - * - * ``` - * number is per friend. File numbers are reused after a transfer terminates. - * Any pattern in file numbers should not be relied on. - * ``` - */ - // @Throws(ToxFileSendException::class) - fun fileSend( - friendNumber: ToxFriendNumber, - kind: Int, - fileSize: Long, - fileId: ToxFileId, - filename: ToxFilename - ): Int - - /** - * Send a chunk of file data to a friend. - * - * This function is called in response to the [[FileChunkRequestCallback]] callback. The length - * parameter should be equal to the one received though the callback. If it is zero, the transfer - * is assumed complete. For files with known size, Core will know that the transfer is complete - * after the last byte has been received, so it is not necessary (though not harmful) to send a - * zero-length chunk to terminate. For streams, core will know that the transfer is finished if a - * chunk with length less than the length requested in the callback is sent. - * - * @param friendNumber The friend number of the receiving friend for this file. - * @param fileNumber The file transfer identifier returned by [[fileSend]]. - * @param position The file or stream position from which the friend should continue writing. - * @param data The chunk data. - */ - // @Throws(ToxFileSendChunkException::class) - fun fileSendChunk( - friendNumber: ToxFriendNumber, - fileNumber: Int, - position: Long, - data: ByteArray - ): Unit - - /** - * Send a custom lossy packet to a friend. - * - * The first byte of data must be in the range 200-254. Maximum length of a custom packet is - * [ [ToxCoreConstants.MaxCustomPacketSize]]. - * - * Lossy packets behave like UDP packets, meaning they might never reach the other side or might - * arrive more than once (if someone is messing with the connection) or might arrive in the wrong - * order. - * - * Unless latency is an issue, it is recommended that you use lossless custom packets instead. - * - * @param friendNumber The friend number of the friend this lossy packet should be sent to. - * @param data A byte array containing the packet data including packet id. - */ - // @Throws(ToxFriendCustomPacketException::class) - fun friendSendLossyPacket(friendNumber: ToxFriendNumber, data: ToxLossyPacket): Unit - - /** - * Send a custom lossless packet to a friend. - * - * The first byte of data must be in the range 160-191. Maximum length of a custom packet is - * [ [ToxCoreConstants.MaxCustomPacketSize]]. - * - * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) but with packets - * instead of a stream. - * - * @param friendNumber The friend number of the friend this lossless packet should be sent to. - * @param data A byte array containing the packet data including packet id. - */ - // @Throws(ToxFriendCustomPacketException::class) - fun friendSendLosslessPacket(friendNumber: ToxFriendNumber, data: ToxLosslessPacket): Unit + /** + * Store all information associated with the tox instance to a byte array. + * + * The data in the byte array can be used to create a new instance with [[load]] by passing it to + * the [[ToxOptions]] constructor. The concrete format in this serialised instance is + * implementation-defined. Passing save data created by one class to a different class may not + * work. + * + * @return a byte array containing the serialised tox instance. + */ + val getSavedata: ByteArray + + /** + * Create a new [[ToxCore]] instance with different options. The implementation may choose to + * create an object of its own class or a different class. If the implementation was compatible + * with another subsystem implementation (e.g. [[im.tox.tox4j.av.ToxAv]]), then the new object + * must be compatible with the same implementation. + * + * This function will bring the instance into a valid state. Running the event loop with a new + * instance will operate correctly. + * + * If the [[ToxOptions.saveData]] field is not empty, this function will load the Tox instance + * from a byte array previously filled by [[getSavedata]]. + * + * If loading failed or succeeded only partially, an exception will be thrown. + * + * @return a new [[ToxCore]] instance. + * @throws ToxNewException + */ + fun load(options: ToxOptions): ToxCore + + /** + * Shut down the tox instance. + * + * Releases all resources associated with the Tox instance and disconnects from the network. + * + * Once this method has been called, all other calls on this instance will throw + * [ [im.tox.tox4j.exceptions.ToxKilledException]]. A closed instance cannot be reused; a new + * instance must be created. + */ + override fun close(): Unit + + /** + * Bootstrap into the tox network. + * + * Sends a "get nodes" request to the given bootstrap node with IP, port, and public key to setup + * connections. + * + * This function will only attempt to connect to the node using UDP. If you want to additionally + * attempt to connect using TCP, use [[addTcpRelay]] together with this function. + * + * @param address the hostname, or an IPv4/IPv6 address of the node. + * @param port the port of the node. + * @param publicKey the public key of the node. + * @throws ToxBootstrapException + */ + fun bootstrap( + address: String, + port: Port, + publicKey: ToxPublicKey, + ): Unit + + /** + * Connect to a TCP relay to forward traffic. + * + * This function can be used to initiate TCP connections to different ports on the same bootstrap + * node, or to add TCP relays without using them as bootstrap nodes. + * + * @param address the hostname, or an IPv4/IPv6 address of the node. + * @param port the TCP port the node is running a relay on. + * @param publicKey the public key of the node. + * @throws ToxBootstrapException + */ + fun addTcpRelay( + address: String, + port: Port, + publicKey: ToxPublicKey, + ): Unit + + /** + * Get the UDP port this instance is bound to. + * + * @return a port number between 1 and 65535. + * @throws ToxGetPortException + */ + val getUdpPort: Port + + /** + * Return the TCP port this Tox instance is bound to. This is only relevant if the instance is + * acting as a TCP relay. + * + * @return a port number between 1 and 65535. + * @throws ToxGetPortException + */ + val getTcpPort: Port + + /** + * Writes the temporary DHT public key of this instance to a byte array. + * + * This can be used in combination with an externally accessible IP address and the bound port + * (from [[getUdpPort]]}) to run a temporary bootstrap node. + * + * Be aware that every time a new instance is created, the DHT public key changes, meaning this + * cannot be used to run a permanent bootstrap node. + * + * @return a byte array of size [[ToxCoreConstants.PUBLIC_KEY_SIZE]] + */ + val getDhtId: ToxPublicKey + + /** + * Get the time in milliseconds until [[iterate]] should be called again for optimal performance. + * + * @return the time in milliseconds until [[iterate]] should be called again. + */ + val iterationInterval: Int + + /** + * The main loop. + * + * This should be invoked every [[iterationInterval]] milliseconds. + */ + fun iterate( + handler: ToxCoreEventListener, + state: S, + ): S + + /** + * Copy the Tox Public Key (long term) from the Tox object. + * + * @return a byte array of size [[ToxCoreConstants.PUBLIC_KEY_SIZE]] + */ + val getPublicKey: ToxPublicKey + + /** + * Copy the Tox Secret Key from the Tox object. + * + * @return a byte array of size [[ToxCoreConstants.SECRET_KEY_SIZE]] + */ + val getSecretKey: ToxSecretKey + + /** + * Set the 4-byte nospam part of the address. + * + * Setting the nospam makes it impossible for others to send us friend requests that contained the + * old nospam number. + * + * @param nospam the new nospam number. + */ + fun setNospam(nospam: Int): Unit + + /** Get our current nospam number. */ + val getNospam: Int + + /** + * Get our current tox address to give to friends. + * + * The format is the following: [Public Key (32 bytes)][noSpam number (4 bytes)][checksum (2 + * bytes)]. After a call to [[setNospam]], the old address can no longer be used to send friend + * requests to this instance. + * + * Note that it is not in a human-readable format. To display it to users, it needs to be + * formatted. + * + * @return a byte array of size [[ToxCoreConstants.ADDRESS_SIZE]] + */ + val getAddress: ToxFriendAddress + + /** + * Set the nickname for the Tox client. + * + * Cannot be longer than [[ToxCoreConstants.MAX_NAME_LENGTH]] bytes. Can be empty (zero-length). + * + * @param name A byte array containing the new nickname.. + * @throws ToxSetInfoException + */ + fun setName(name: ToxNickname): Unit + + /** Get our own nickname. */ + val getName: ToxNickname + + /** + * Set our status message. + * + * Cannot be longer than [[ToxCoreConstants.MAX_STATUS_MESSAGE_LENGTH]] bytes. + * + * @param message the status message to set. + * @throws ToxSetInfoException + */ + fun setStatusMessage(message: ToxStatusMessage): Unit + + /** Gets our own status message. May be null if the status message was empty. */ + val getStatusMessage: ToxStatusMessage + + /** + * Set our status. + * + * @param status status to set. + */ + fun setStatus(status: ToxUserStatus): Unit + + /** Get our status. */ + val getStatus: ToxUserStatus + + /** + * Add a friend to the friend list and send a friend request. + * + * A friend request message must be at least 1 byte long and at most + * [ [ToxCoreConstants.MAX_FRIEND_REQUEST_LENGTH]]. + * + * Friend numbers are unique identifiers used in all functions that operate on friends. Once + * added, a friend number is stable for the lifetime of the Tox object. After saving the state and + * reloading it, the friend numbers may not be the same as before. Deleting a friend creates a gap + * in the friend number set, which is filled by the next adding of a friend. Any pattern in friend + * numbers should not be relied on. + * + * If more than [[Int.MaxValue]] friends are added, this function throws an exception. + * + * @param address the address to add as a friend ([[ToxCoreConstants.ADDRESS_SIZE]] bytes). + * + * ``` + * This is the byte array the friend got from their own [[getAddress]]. + * @param message + * ``` + * + * the message to send with the friend request (must not be empty). + * + * @return the new friend's friend number. + * @throws ToxFriendAddException + * @throws IllegalArgumentException + */ + fun addFriend( + address: ToxFriendAddress, + message: ToxFriendRequestMessage, + ): ToxFriendNumber + + /** + * Add a friend without sending a friend request. + * + * This function is used to add a friend in response to a friend request. If the client receives a + * friend request, it can be reasonably sure that the other client added this client as a friend, + * eliminating the need for a friend request. + * + * This function is also useful in a situation where both instances are controlled by the same + * entity, so that this entity can perform the mutual friend adding. In this case, there is no + * need for a friend request, either. + * + * @param publicKey the Public Key to add as a friend ([[ToxCoreConstants.PUBLIC_KEY_SIZE]] bytes). + * @return the new friend's friend number. + * @throws ToxFriendAddException + * @throws IllegalArgumentException + */ + fun addFriendNorequest(publicKey: ToxPublicKey): ToxFriendNumber + + /** + * Remove a friend from the friend list. + * + * This does not notify the friend of their deletion. After calling this function, this client + * will appear offline to the friend and no communication can occur between the two. + * + * @param friendNumber the friend number to delete. + * @throws ToxFriendDeleteException + */ + fun deleteFriend(friendNumber: ToxFriendNumber): Unit + + /** + * Gets the friend number for the specified Public Key. + * + * @param publicKey the Public Key. + * @return the friend number that is associated with the Public Key. + * @throws ToxFriendByPublicKeyException + */ + fun friendByPublicKey(publicKey: ToxPublicKey): ToxFriendNumber + + /** + * Gets the Public Key for the specified friend number. + * + * @param friendNumber the friend number. + * @return the Public Key associated with the friend number. + * @throws ToxFriendGetPublicKeyException + */ + fun getFriendPublicKey(friendNumber: ToxFriendNumber): ToxPublicKey + + /** + * Checks whether a friend with the specified friend number exists. + * + * If this function returns true, the return value is valid until the friend is + * deleted. If false is returned, the return value is valid until either of + * [ [addFriend]] or [[addFriendNorequest]] is invoked. + * + * @param friendNumber the friend number to check. + * @return true if such a friend exists. + */ + fun friendExists(friendNumber: ToxFriendNumber): Boolean + + /** + * Get an array of currently valid friend numbers. + * + * This list is valid until either of the following is invoked: [[deleteFriend]], [[addFriend]], + * [ [addFriendNorequest]]. + * + * @return an array containing the currently valid friend numbers, the empty int array if there + * are no friends. + */ + val getFriendList: IntArray + + /** + * Get an array of [[ToxFriendNumber]] objects with the same values as [[getFriendList]]. + * + * This method exists for Java compatibility, because [[getFriendList]] must return an int array. + * + * @return [[getFriendList]] mapped to [[ToxFriendNumber]]. + */ + val getFriendNumbers: List + get() = getFriendList.map { ToxFriendNumber(it) } + + /** + * Tell friend number whether or not we are currently typing. + * + * The client is responsible for turning it on or off. + * + * @param friendNumber the friend number to set typing status for. + * @param typing true if we are currently typing. + * @throws ToxSetTypingException + */ + fun setTyping( + friendNumber: ToxFriendNumber, + typing: Boolean, + ): Unit + + /** + * Send a text chat message to an online friend. + * + * This function creates a chat message packet and pushes it into the send queue. + * + * The message length may not exceed [[ToxCoreConstants.MAX_MESSAGE_LENGTH]]. Larger messages must + * be split by the client and sent as separate messages. Other clients can then reassemble the + * fragments. Messages may not be empty. + * + * The return value of this function is the message ID. If a read receipt is received, the + * triggered [[FriendReadReceiptCallback]] event will be passed this message ID. + * + * Message IDs are unique per friend per instance. The first message ID is 0. Message IDs are + * incremented by 1 each time a message is sent. If [[Int.MaxValue]] messages were sent, the next + * message ID is [[Int.MinValue]]. + * + * Message IDs are not stored in the array returned by [[getSavedata]]. + * + * @param friendNumber The friend number of the friend to send the message to. + * @param messageType Message type (normal, action, ...). + * @param timeDelta The time between composition (user created the message) and calling this + * function. + * @param message The message text + * @return the message ID. + * @throws ToxFriendSendMessageException + */ + fun friendSendMessage( + friendNumber: ToxFriendNumber, + messageType: ToxMessageType, + timeDelta: Int, + message: ToxFriendMessage, + ): Int + + /** + * Sends a file control command to a friend for a given file transfer. + * + * @param friendNumber The friend number of the friend the file is being transferred to or + * received from. + * @param fileNumber The friend-specific identifier for the file transfer. + * @param control The control command to send. + * @throws ToxFileControlException + */ + fun fileControl( + friendNumber: ToxFriendNumber, + fileNumber: Int, + control: ToxFileControl, + ): Unit + + /** + * Sends a file seek control command to a friend for a given file transfer. + * + * This function can only be called to resume a file transfer right before + * [ [ToxFileControl.RESUME]] is sent. + * + * @param friendNumber The friend number of the friend the file is being received from. + * @param fileNumber The friend-specific identifier for the file transfer. + * @param position The position that the file should be seeked to. + * @throws ToxFileSeekException + */ + fun fileSeek( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + ): Unit + + /** + * Return the file id associated to the file transfer as a byte array. + * + * @param friendNumber The friend number of the friend the file is being transferred to or + * received from. + * @param fileNumber The friend-specific identifier for the file transfer. + * @throws ToxFileGetException + */ + fun getFileFileId( + friendNumber: ToxFriendNumber, + fileNumber: Int, + ): ToxFileId + + /** + * Send a file transmission request. + * + * Maximum filename length is [[ToxCoreConstants.MAX_FILENAME_LENGTH]] bytes. The filename should + * generally just be a file name, not a path with directory names. + * + * If a non-negative file size is provided, it can be used by both sides to determine the sending + * progress. File size can be set to a negative value for streaming data of unknown size. + * + * File transmission occurs in chunks, which are requested through the [[FileChunkRequestCallback] + * ] event. + * + * When a friend goes offline, all file transfers associated with the friend are purged from core. + * + * If the file contents change during a transfer, the behaviour is unspecified in general. What + * will actually happen depends on the mode in which the file was modified and how the client + * determines the file size. + * - If the file size was increased + * - and sending mode was streaming (fileSize = -1), the behaviour + * + * ``` + * will be as expected. + * ``` + * - and sending mode was file (fileSize != -1), the + * + * ``` + * [[FileChunkRequestCallback]] callback will receive length = 0 when Core thinks + * the file transfer has finished. If the client remembers the file size as + * it was when sending the request, it will terminate the transfer normally. + * If the client re-reads the size, it will think the friend cancelled the + * transfer. + * ``` + * - If the file size was decreased + * - and sending mode was streaming, the behaviour is as expected. + * - and sending mode was file, the callback will return 0 at the new + * + * ``` + * (earlier) end-of-file, signalling to the friend that the transfer was + * cancelled. + * ``` + * - If the file contents were modified + * - at a position before the current read, the two files (local and remote) + * + * ``` + * will differ after the transfer terminates. + * ``` + * - at a position after the current read, the file transfer will succeed as + * + * ``` + * expected. + * ``` + * - In either case, both sides will regard the transfer as complete and + * + * ``` + * successful. + * + * @param friendNumber + * ``` + * + * The friend number of the friend the file send request should be sent to. + * + * @param kind The meaning of the file to be sent. + * @param fileSize Size in bytes of the file the client wants to send, -1 if unknown or streaming. + * @param fileId A file identifier of length [[ToxCoreConstants.FILE_ID_LENGTH]] that can be used to + * + * ``` + * uniquely identify file transfers across core restarts. If empty, a random one will + * be generated by core. It can then be obtained by using [[getFileFileId]] + * @param filename + * ``` + * + * Name of the file. Does not need to be the actual name. This + * + * ``` + * name will be sent along with the file send request. + * @return + * ``` + * + * A file number used as an identifier in subsequent callbacks. This + * + * ``` + * number is per friend. File numbers are reused after a transfer terminates. + * Any pattern in file numbers should not be relied on. + * ``` + * @throws ToxFileSendException + */ + fun fileSend( + friendNumber: ToxFriendNumber, + kind: Int, + fileSize: Long, + fileId: ToxFileId, + filename: ToxFilename, + ): Int + + /** + * Send a chunk of file data to a friend. + * + * This function is called in response to the [[FileChunkRequestCallback]] callback. The length + * parameter should be equal to the one received though the callback. If it is zero, the transfer + * is assumed complete. For files with known size, Core will know that the transfer is complete + * after the last byte has been received, so it is not necessary (though not harmful) to send a + * zero-length chunk to terminate. For streams, core will know that the transfer is finished if a + * chunk with length less than the length requested in the callback is sent. + * + * @param friendNumber The friend number of the receiving friend for this file. + * @param fileNumber The file transfer identifier returned by [[fileSend]]. + * @param position The file or stream position from which the friend should continue writing. + * @param data The chunk data. + * @throws ToxFileSendChunkException + */ + fun fileSendChunk( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + data: ByteArray, + ): Unit + + /** + * Send a custom lossy packet to a friend. + * + * The first byte of data must be in the range 200-254. Maximum length of a custom packet is + * [ [ToxCoreConstants.MAX_CUSTOM_PACKET_SIZE]]. + * + * Lossy packets behave like UDP packets, meaning they might never reach the other side or might + * arrive more than once (if someone is messing with the connection) or might arrive in the wrong + * order. + * + * Unless latency is an issue, it is recommended that you use lossless custom packets instead. + * + * @param friendNumber The friend number of the friend this lossy packet should be sent to. + * @param data A byte array containing the packet data including packet id. + * @throws ToxFriendCustomPacketException + */ + fun friendSendLossyPacket( + friendNumber: ToxFriendNumber, + data: ToxLossyPacket, + ): Unit + + /** + * Send a custom lossless packet to a friend. + * + * The first byte of data must be in the range 160-191. Maximum length of a custom packet is + * [ [ToxCoreConstants.MAX_CUSTOM_PACKET_SIZE]]. + * + * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) but with packets + * instead of a stream. + * + * @param friendNumber The friend number of the friend this lossless packet should be sent to. + * @param data A byte array containing the packet data including packet id. + * @throws ToxFriendCustomPacketException + */ + fun friendSendLosslessPacket( + friendNumber: ToxFriendNumber, + data: ToxLosslessPacket, + ): Unit } diff --git a/lib/src/main/java/im/tox/tox4j/core/ToxCoreConstants.kt b/lib/src/main/java/im/tox/tox4j/core/ToxCoreConstants.kt index 11be0a062..e6cc4f687 100644 --- a/lib/src/main/java/im/tox/tox4j/core/ToxCoreConstants.kt +++ b/lib/src/main/java/im/tox/tox4j/core/ToxCoreConstants.kt @@ -3,59 +3,58 @@ package im.tox.tox4j.core import im.tox.tox4j.crypto.ToxCryptoConstants object ToxCoreConstants { + /** The size of a Tox Public Key in bytes. */ + const val PUBLIC_KEY_SIZE = ToxCryptoConstants.PUBLIC_KEY_LENGTH - /** The size of a Tox Public Key in bytes. */ - const val PublicKeySize = ToxCryptoConstants.PublicKeyLength + /** The size of a Tox Secret Key in bytes. */ + const val SECRET_KEY_SIZE = ToxCryptoConstants.SECRET_KEY_LENGTH - /** The size of a Tox Secret Key in bytes. */ - const val SecretKeySize = ToxCryptoConstants.SecretKeyLength + /** + * The size of a Tox address in bytes. Tox addresses are in the format + * [Public Key ([ [PUBLIC_KEY_SIZE]] bytes)][nospam (4 bytes)][checksum (2 bytes)]. + * + * The checksum is computed over the Public Key and the nospam value. The first byte is an XOR of + * all the odd bytes, the second byte is an XOR of all the even bytes of the Public Key and + * nospam. + */ + const val ADDRESS_SIZE = PUBLIC_KEY_SIZE + 4 + 2 - /** - * The size of a Tox address in bytes. Tox addresses are in the format - * [Public Key ([ [PublicKeySize]] bytes)][nospam (4 bytes)][checksum (2 bytes)]. - * - * The checksum is computed over the Public Key and the nospam value. The first byte is an XOR of - * all the odd bytes, the second byte is an XOR of all the even bytes of the Public Key and - * nospam. - */ - const val AddressSize = PublicKeySize + 4 + 2 + /** Maximum length of a nickname in bytes. */ + const val MAX_NAME_LENGTH = 128 - /** Maximum length of a nickname in bytes. */ - const val MaxNameLength = 128 + /** Maximum length of a status message in bytes. */ + const val MAX_STATUS_MESSAGE_LENGTH = 1007 - /** Maximum length of a status message in bytes. */ - const val MaxStatusMessageLength = 1007 + /** Maximum length of a friend request message in bytes. */ + const val MAX_FRIEND_REQUEST_LENGTH = 1016 - /** Maximum length of a friend request message in bytes. */ - const val MaxFriendRequestLength = 1016 + /** Maximum length of a single message after which it should be split. */ + const val MAX_MESSAGE_LENGTH = 1372 - /** Maximum length of a single message after which it should be split. */ - const val MaxMessageLength = 1372 + /** Maximum size of custom packets. */ + const val MAX_CUSTOM_PACKET_SIZE = 1373 - /** Maximum size of custom packets. */ - const val MaxCustomPacketSize = 1373 + /** Maximum file name length for file transfers. */ + const val MAX_FILENAME_LENGTH = 255 - /** Maximum file name length for file transfers. */ - const val MaxFilenameLength = 255 + /** + * Maximum hostname length. This is determined by calling `getconf HOST_NAME_MAX` on the console. + * The value presented here is valid for most systems. + */ + const val MAX_HOSTNAME_LENGTH = 255 - /** - * Maximum hostname length. This is determined by calling `getconf HOST_NAME_MAX` on the console. - * The value presented here is valid for most systems. - */ - const val MaxHostnameLength = 255 + /** The number of bytes in a file id. */ + const val FILE_ID_LENGTH = ToxCryptoConstants.HASH_LENGTH - /** The number of bytes in a file id. */ - const val FileIdLength = ToxCryptoConstants.HashLength + /** Default port for HTTP proxies. */ + const val DEFAULT_PROXY_PORT: UShort = 8080u - /** Default port for HTTP proxies. */ - val DefaultProxyPort = 8080.toUShort() + /** Default start port for Tox UDP sockets. */ + const val DEFAULT_START_PORT: UShort = 33445u - /** Default start port for Tox UDP sockets. */ - val DefaultStartPort = 33445.toUShort() + /** Default end port for Tox UDP sockets. */ + val DEFAULT_END_PORT: UShort = (DEFAULT_START_PORT + 100u).toUShort() - /** Default end port for Tox UDP sockets. */ - val DefaultEndPort = (DefaultStartPort + 100.toUShort()).toUShort() - - /** Default port for Tox TCP relays. A value of 0 means disabled. */ - val DefaultTcpPort = 0.toUShort() + /** Default port for Tox TCP relays. A value of 0 means disabled. */ + const val DEFAULT_TCP_PORT: UShort = 0u } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileChunkRequestCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileChunkRequestCallback.kt index 3f360cba4..79559430d 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileChunkRequestCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileChunkRequestCallback.kt @@ -4,33 +4,33 @@ import im.tox.tox4j.core.data.ToxFriendNumber /** This event is triggered when Core is ready to send more file data. */ interface FileChunkRequestCallback { - /** - * If the length parameter is 0, the file transfer is finished, and the client's resources - * associated with the file number should be released. After a call with zero length, the file - * number can be reused for future file transfers. - * - * If the requested position is not equal to the client's idea of the current file or stream - * position, it will need to seek. In case of read-once streams, the client should keep the last - * read chunk so that a seek back can be supported. A seek-back only ever needs to read from the - * last requested chunk. This happens when a chunk was requested, but the send failed. A seek-back - * request can occur an arbitrary number of times for any given chunk. - * - * In response to receiving this callback, the client should call the function - * [ [ToxCore.fileSendChunk]] with the requested chunk. If the number of bytes sent through that - * function is zero, the file transfer is assumed complete. A client must send the full length of - * data requested with this callback. - * - * @param friendNumber The friend number of the receiving friend for this file. - * @param fileNumber The file transfer identifier returned by { @link - * im.tox.tox4j.core.ToxCore#fileSend}. - * @param position The file or stream position from which to continue reading. - * @param length The number of bytes requested for the current chunk. - */ - fun fileChunkRequest( - friendNumber: ToxFriendNumber, - fileNumber: Int, - position: Long, - length: Int, - state: ToxCoreState - ): ToxCoreState = state + /** + * If the length parameter is 0, the file transfer is finished, and the client's resources + * associated with the file number should be released. After a call with zero length, the file + * number can be reused for future file transfers. + * + * If the requested position is not equal to the client's idea of the current file or stream + * position, it will need to seek. In case of read-once streams, the client should keep the last + * read chunk so that a seek back can be supported. A seek-back only ever needs to read from the + * last requested chunk. This happens when a chunk was requested, but the send failed. A seek-back + * request can occur an arbitrary number of times for any given chunk. + * + * In response to receiving this callback, the client should call the function + * [ [ToxCore.fileSendChunk]] with the requested chunk. If the number of bytes sent through that + * function is zero, the file transfer is assumed complete. A client must send the full length of + * data requested with this callback. + * + * @param friendNumber The friend number of the receiving friend for this file. + * @param fileNumber The file transfer identifier returned by { @link + * im.tox.tox4j.core.ToxCore#fileSend}. + * @param position The file or stream position from which to continue reading. + * @param length The number of bytes requested for the current chunk. + */ + fun fileChunkRequest( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + length: Int, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvCallback.kt index 2d1a0055c..6bc4fb5a7 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvCallback.kt @@ -6,25 +6,25 @@ import im.tox.tox4j.core.enums.ToxFileControl /** This event is triggered when a file transfer request is received. */ interface FileRecvCallback { - /** - * The client should acquire resources to be associated with the file transfer. Incoming file - * transfers start in the PAUSED state. After this callback returns, a transfer can be rejected by - * sending a [[ToxFileControl.CANCEL]] control command before any other control commands. It can - * be accepted by sending [[ToxFileControl.RESUME]]. - * - * @param friendNumber The friend number of the friend who is sending the file transfer request. - * @param fileNumber The friend-specific file number the data received is associated with. - * @param kind The meaning of the file to be sent. - * @param fileSize Size in bytes of the file the client wants to send, -1 if unknown or streaming. - * @param filename Name of the file. May not be the actual name. This name was sent along with the - * file send request. - */ - fun fileRecv( - friendNumber: ToxFriendNumber, - fileNumber: Int, - kind: Int, - fileSize: Long, - filename: ToxFilename, - state: ToxCoreState - ): ToxCoreState = state + /** + * The client should acquire resources to be associated with the file transfer. Incoming file + * transfers start in the PAUSED state. After this callback returns, a transfer can be rejected by + * sending a [[ToxFileControl.CANCEL]] control command before any other control commands. It can + * be accepted by sending [[ToxFileControl.RESUME]]. + * + * @param friendNumber The friend number of the friend who is sending the file transfer request. + * @param fileNumber The friend-specific file number the data received is associated with. + * @param kind The meaning of the file to be sent. + * @param fileSize Size in bytes of the file the client wants to send, -1 if unknown or streaming. + * @param filename Name of the file. May not be the actual name. This name was sent along with the + * file send request. + */ + fun fileRecv( + friendNumber: ToxFriendNumber, + fileNumber: Int, + kind: Int, + fileSize: Long, + filename: ToxFilename, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvChunkCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvChunkCallback.kt index ff6f819c5..e70c47d3b 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvChunkCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvChunkCallback.kt @@ -7,25 +7,25 @@ import im.tox.tox4j.core.data.ToxFriendNumber * chunk of file data for an accepted request was received. */ interface FileRecvChunkCallback { - /** - * When length is 0, the transfer is finished and the client should release the resources it - * acquired for the transfer. After a call with length = 0, the file number can be reused for new - * file transfers. - * - * If position is equal to file_size (received in the [[FileRecvCallback]] callback) when the - * transfer finishes, the file was received completely. Otherwise, if fileSize was negative, - * streaming ended successfully when length is 0. - * - * @param friendNumber The friend number of the friend who is sending the file. - * @param fileNumber The friend-specific file number the data received is associated with. - * @param position The file position of the first byte in data. - * @param data A byte array containing the received chunk. - */ - fun fileRecvChunk( - friendNumber: ToxFriendNumber, - fileNumber: Int, - position: Long, - data: ByteArray, - state: ToxCoreState - ): ToxCoreState = state + /** + * When length is 0, the transfer is finished and the client should release the resources it + * acquired for the transfer. After a call with length = 0, the file number can be reused for new + * file transfers. + * + * If position is equal to file_size (received in the [[FileRecvCallback]] callback) when the + * transfer finishes, the file was received completely. Otherwise, if fileSize was negative, + * streaming ended successfully when length is 0. + * + * @param friendNumber The friend number of the friend who is sending the file. + * @param fileNumber The friend-specific file number the data received is associated with. + * @param position The file position of the first byte in data. + * @param data A byte array containing the received chunk. + */ + fun fileRecvChunk( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + data: ByteArray, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvControlCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvControlCallback.kt index 38f29036d..502c22089 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvControlCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FileRecvControlCallback.kt @@ -5,18 +5,18 @@ import im.tox.tox4j.core.enums.ToxFileControl /** This event is triggered when a file control command is received from a friend. */ interface FileRecvControlCallback { - /** - * When receiving [[ToxFileControl.CANCEL]], the client should release the resources associated - * with the file number and consider the transfer failed. - * - * @param friendNumber The friend number of the friend who is sending the file. - * @param fileNumber The friend-specific file number the data received is associated with. - * @param control The file control command received. - */ - fun fileRecvControl( - friendNumber: ToxFriendNumber, - fileNumber: Int, - control: ToxFileControl, - state: ToxCoreState - ): ToxCoreState = state + /** + * When receiving [[ToxFileControl.CANCEL]], the client should release the resources associated + * with the file number and consider the transfer failed. + * + * @param friendNumber The friend number of the friend who is sending the file. + * @param fileNumber The friend-specific file number the data received is associated with. + * @param control The file control command received. + */ + fun fileRecvControl( + friendNumber: ToxFriendNumber, + fileNumber: Int, + control: ToxFileControl, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendConnectionStatusCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendConnectionStatusCallback.kt index a2ca3124a..ff2b5ce0b 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendConnectionStatusCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendConnectionStatusCallback.kt @@ -11,13 +11,13 @@ import im.tox.tox4j.core.enums.ToxConnection * connection status is initially offline. */ interface FriendConnectionStatusCallback { - /** - * @param friendNumber The friend number of the friend whose connection status changed. - * @param connectionStatus The new connection status. - */ - fun friendConnectionStatus( - friendNumber: ToxFriendNumber, - connectionStatus: ToxConnection, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend whose connection status changed. + * @param connectionStatus The new connection status. + */ + fun friendConnectionStatus( + friendNumber: ToxFriendNumber, + connectionStatus: ToxConnection, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLosslessPacketCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLosslessPacketCallback.kt index 9e74a152a..06623b62c 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLosslessPacketCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLosslessPacketCallback.kt @@ -5,13 +5,13 @@ import im.tox.tox4j.core.data.ToxLosslessPacket /** This event is triggered when a custom lossless packet arrives from a friend. */ interface FriendLosslessPacketCallback { - /** - * @param friendNumber The friend number of the friend who sent a lossless packet. - * @param data A byte array containing the received packet data. The first byte is the packet id. - */ - fun friendLosslessPacket( - friendNumber: ToxFriendNumber, - data: ToxLosslessPacket, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who sent a lossless packet. + * @param data A byte array containing the received packet data. The first byte is the packet id. + */ + fun friendLosslessPacket( + friendNumber: ToxFriendNumber, + data: ToxLosslessPacket, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLossyPacketCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLossyPacketCallback.kt index 74433c48e..a6db2d44b 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLossyPacketCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendLossyPacketCallback.kt @@ -5,13 +5,13 @@ import im.tox.tox4j.core.data.ToxLossyPacket /** This event is triggered when a custom lossy packet arrives from a friend. */ interface FriendLossyPacketCallback { - /** - * @param friendNumber The friend number of the friend who sent a lossy packet. - * @param data A byte array containing the received packet data. The first byte is the packet id. - */ - fun friendLossyPacket( - friendNumber: ToxFriendNumber, - data: ToxLossyPacket, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who sent a lossy packet. + * @param data A byte array containing the received packet data. The first byte is the packet id. + */ + fun friendLossyPacket( + friendNumber: ToxFriendNumber, + data: ToxLossyPacket, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendMessageCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendMessageCallback.kt index 1c4b8094d..4a4f2a339 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendMessageCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendMessageCallback.kt @@ -6,26 +6,26 @@ import im.tox.tox4j.core.enums.ToxMessageType /** This event is triggered when a message from a friend is received. */ interface FriendMessageCallback { - /** - * @param friendNumber The friend number of the friend who sent the message. - * @param messageType Message type (normal, action, ...). - * @param timeDelta A delta in seconds between when the message was composed - * - * ``` - * and when it is being transmitted. For messages that are sent immediately, - * it will be 0. If a message was written and couldn't be sent immediately - * (due to a connection failure, for example), the timeDelta is an - * approximation of when it was composed. - * @param message - * ``` - * - * The message data they sent. - */ - fun friendMessage( - friendNumber: ToxFriendNumber, - messageType: ToxMessageType, - timeDelta: Int, - message: ToxFriendMessage, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who sent the message. + * @param messageType Message type (normal, action, ...). + * @param timeDelta A delta in seconds between when the message was composed + * + * ``` + * and when it is being transmitted. For messages that are sent immediately, + * it will be 0. If a message was written and couldn't be sent immediately + * (due to a connection failure, for example), the timeDelta is an + * approximation of when it was composed. + * @param message + * ``` + * + * The message data they sent. + */ + fun friendMessage( + friendNumber: ToxFriendNumber, + messageType: ToxMessageType, + timeDelta: Int, + message: ToxFriendMessage, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendNameCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendNameCallback.kt index 2a67b9e5a..0b496a8be 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendNameCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendNameCallback.kt @@ -5,13 +5,13 @@ import im.tox.tox4j.core.data.ToxNickname /** This event is triggered when a friend changes their name. */ interface FriendNameCallback { - /** - * @param friendNumber The friend number of the friend whose name changed. - * @param name The new nickname. - */ - fun friendName( - friendNumber: ToxFriendNumber, - name: ToxNickname, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend whose name changed. + * @param name The new nickname. + */ + fun friendName( + friendNumber: ToxFriendNumber, + name: ToxNickname, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendReadReceiptCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendReadReceiptCallback.kt index 64510c4d4..c2a01c373 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendReadReceiptCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendReadReceiptCallback.kt @@ -7,14 +7,14 @@ import im.tox.tox4j.core.data.ToxFriendNumber * [ [ToxCore.friendSendMessage]] with the corresponding message ID. */ interface FriendReadReceiptCallback { - /** - * @param friendNumber The friend number of the friend who received the message. - * @param messageId The message ID as returned from [[ToxCore.friendSendMessage]] corresponding to - * the message sent. - */ - fun friendReadReceipt( - friendNumber: ToxFriendNumber, - messageId: Int, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who received the message. + * @param messageId The message ID as returned from [[ToxCore.friendSendMessage]] corresponding to + * the message sent. + */ + fun friendReadReceipt( + friendNumber: ToxFriendNumber, + messageId: Int, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendRequestCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendRequestCallback.kt index d2bfbe9fa..15d4db838 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendRequestCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendRequestCallback.kt @@ -5,21 +5,21 @@ import im.tox.tox4j.core.data.ToxPublicKey /** This event is triggered when a friend request is received. */ interface FriendRequestCallback { - /** - * @param publicKey The Public Key of the user who sent the friend request. - * @param timeDelta A delta in seconds between when the message was composed - * - * ``` - * and when it is being transmitted. - * @param message - * ``` - * - * The message they sent along with the request. - */ - fun friendRequest( - publicKey: ToxPublicKey, - timeDelta: Int, - message: ToxFriendRequestMessage, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param publicKey The Public Key of the user who sent the friend request. + * @param timeDelta A delta in seconds between when the message was composed + * + * ``` + * and when it is being transmitted. + * @param message + * ``` + * + * The message they sent along with the request. + */ + fun friendRequest( + publicKey: ToxPublicKey, + timeDelta: Int, + message: ToxFriendRequestMessage, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusCallback.kt index 8070181b6..f8e54573c 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusCallback.kt @@ -5,13 +5,13 @@ import im.tox.tox4j.core.enums.ToxUserStatus /** This event is triggered when a friend changes their user status. */ interface FriendStatusCallback { - /** - * @param friendNumber The friend number of the friend whose user status changed. - * @param status The new user status. - */ - fun friendStatus( - friendNumber: ToxFriendNumber, - status: ToxUserStatus, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend whose user status changed. + * @param status The new user status. + */ + fun friendStatus( + friendNumber: ToxFriendNumber, + status: ToxUserStatus, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusMessageCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusMessageCallback.kt index 521eb79e6..aa87bf2fe 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusMessageCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendStatusMessageCallback.kt @@ -5,13 +5,13 @@ import im.tox.tox4j.core.data.ToxStatusMessage /** This event is triggered when a friend changes their status message. */ interface FriendStatusMessageCallback { - /** - * @param friendNumber The friend number of the friend whose status message changed. - * @param message The new status message. - */ - fun friendStatusMessage( - friendNumber: ToxFriendNumber, - message: ToxStatusMessage, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend whose status message changed. + * @param message The new status message. + */ + fun friendStatusMessage( + friendNumber: ToxFriendNumber, + message: ToxStatusMessage, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendTypingCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendTypingCallback.kt index d85ae48f6..249d5f2a7 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendTypingCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/FriendTypingCallback.kt @@ -4,13 +4,13 @@ import im.tox.tox4j.core.data.ToxFriendNumber /** This event is triggered when a friend starts or stops typing. */ interface FriendTypingCallback { - /** - * @param friendNumber The friend number of the friend who started or stopped typing. - * @param isTyping Whether the friend started (true) or stopped (false) typing. - */ - fun friendTyping( - friendNumber: ToxFriendNumber, - isTyping: Boolean, - state: ToxCoreState - ): ToxCoreState = state + /** + * @param friendNumber The friend number of the friend who started or stopped typing. + * @param isTyping Whether the friend started (true) or stopped (false) typing. + */ + fun friendTyping( + friendNumber: ToxFriendNumber, + isTyping: Boolean, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/callbacks/SelfConnectionStatusCallback.kt b/lib/src/main/java/im/tox/tox4j/core/callbacks/SelfConnectionStatusCallback.kt index 7dd7424fc..5268afdb6 100644 --- a/lib/src/main/java/im/tox/tox4j/core/callbacks/SelfConnectionStatusCallback.kt +++ b/lib/src/main/java/im/tox/tox4j/core/callbacks/SelfConnectionStatusCallback.kt @@ -9,9 +9,9 @@ import im.tox.tox4j.core.enums.ToxConnection * not immediately bootstrap on receiving a disconnect. */ interface SelfConnectionStatusCallback { - /** @param connectionStatus The new connection status. */ - fun selfConnectionStatus( - connectionStatus: ToxConnection, - state: ToxCoreState, - ): ToxCoreState = state + /** @param connectionStatus The new connection status. */ + fun selfConnectionStatus( + connectionStatus: ToxConnection, + state: ToxCoreState, + ): ToxCoreState = state } diff --git a/lib/src/main/java/im/tox/tox4j/core/options/ProxyOptions.kt b/lib/src/main/java/im/tox/tox4j/core/options/ProxyOptions.kt index a1ba8d4d1..aaf51be69 100644 --- a/lib/src/main/java/im/tox/tox4j/core/options/ProxyOptions.kt +++ b/lib/src/main/java/im/tox/tox4j/core/options/ProxyOptions.kt @@ -4,52 +4,52 @@ import im.tox.tox4j.core.enums.ToxProxyType /** Proxy options for [[ToxCore.load]] */ object ProxyOptions { - /** Base type for all proxy kinds. */ - sealed interface Type { - /** Low level enumeration value to pass to [[ToxCore.load]]. */ - val proxyType: ToxProxyType + /** Base type for all proxy kinds. */ + sealed interface Type { + /** Low level enumeration value to pass to [[ToxCore.load]]. */ + val proxyType: ToxProxyType - /** - * The IP address or DNS name of the proxy to be used. - * - * If used, this must be a valid DNS name. The name must not exceed - * [ [ToxCoreConstants.MaxHostnameLength]] characters. This member is ignored (it can be - * anything) if [[proxyType]] is [[ToxProxyType.NONE]]. - */ - val proxyAddress: String + /** + * The IP address or DNS name of the proxy to be used. + * + * If used, this must be a valid DNS name. The name must not exceed + * [ [ToxCoreConstants.MaxHostnameLength]] characters. This member is ignored (it can be + * anything) if [[proxyType]] is [[ToxProxyType.NONE]]. + */ + val proxyAddress: String - /** - * The port to use to connect to the proxy server. - * - * Ports must be in the range (1, 65535). The value is ignored if [[proxyType]] is - * [ [ToxProxyType.NONE]]. - */ - val proxyPort: UShort - } + /** + * The port to use to connect to the proxy server. + * + * Ports must be in the range (1, 65535). The value is ignored if [[proxyType]] is + * [ [ToxProxyType.NONE]]. + */ + val proxyPort: UShort + } - /** Don't use a proxy. Attempt to directly connect to other nodes. */ - object None : Type { - override val proxyType: ToxProxyType = ToxProxyType.NONE - override val proxyAddress: String = "" - override val proxyPort: UShort = 0.toUShort() - } + /** Don't use a proxy. Attempt to directly connect to other nodes. */ + object None : Type { + override val proxyType: ToxProxyType = ToxProxyType.NONE + override val proxyAddress: String = "" + override val proxyPort: UShort = 0.toUShort() + } - /** Tunnel Tox TCP traffic over an HTTP proxy. The proxy must support CONNECT. */ - final data class Http( - override val proxyAddress: String, - override val proxyPort: UShort, - ) : Type { - override val proxyType: ToxProxyType = ToxProxyType.HTTP - } + /** Tunnel Tox TCP traffic over an HTTP proxy. The proxy must support CONNECT. */ + final data class Http( + override val proxyAddress: String, + override val proxyPort: UShort, + ) : Type { + override val proxyType: ToxProxyType = ToxProxyType.HTTP + } - /** - * Use a SOCKS5 proxy to make TCP connections. Although some SOCKS5 servers support UDP sockets, - * the main use case (Tor) does not, and Tox will not use the proxy for UDP connections. - */ - final data class Socks5( - override val proxyAddress: String, - override val proxyPort: UShort, - ) : Type { - override val proxyType: ToxProxyType = ToxProxyType.SOCKS5 - } + /** + * Use a SOCKS5 proxy to make TCP connections. Although some SOCKS5 servers support UDP sockets, + * the main use case (Tor) does not, and Tox will not use the proxy for UDP connections. + */ + final data class Socks5( + override val proxyAddress: String, + override val proxyPort: UShort, + ) : Type { + override val proxyType: ToxProxyType = ToxProxyType.SOCKS5 + } } diff --git a/lib/src/main/java/im/tox/tox4j/core/options/SaveDataOptions.kt b/lib/src/main/java/im/tox/tox4j/core/options/SaveDataOptions.kt index 694827b70..f2a206c60 100644 --- a/lib/src/main/java/im/tox/tox4j/core/options/SaveDataOptions.kt +++ b/lib/src/main/java/im/tox/tox4j/core/options/SaveDataOptions.kt @@ -4,38 +4,39 @@ import im.tox.tox4j.core.data.ToxSecretKey import im.tox.tox4j.core.enums.ToxSavedataType /** Base type for all save data kinds. */ +@Suppress("ktlint:standard:no-consecutive-comments") object SaveDataOptions { - sealed interface Type { - /** The low level [[ToxSavedataType]] enum to pass to [[ToxCore.load]]. */ - val kind: ToxSavedataType + sealed interface Type { + /** The low level [[ToxSavedataType]] enum to pass to [[ToxCore.load]]. */ + val kind: ToxSavedataType - /** Serialised save data. The format depends on [[kind]]. */ - val data: ByteArray - } + /** Serialised save data. The format depends on [[kind]]. */ + val data: ByteArray + } - /** The various kinds of save data that can be loaded by [[ToxCore.load]]. */ + /** The various kinds of save data that can be loaded by [[ToxCore.load]]. */ - /** No save data. */ - object None : Type { - override val kind: ToxSavedataType = ToxSavedataType.NONE - override val data: ByteArray = byteArrayOf() - } + /** No save data. */ + object None : Type { + override val kind: ToxSavedataType = ToxSavedataType.NONE + override val data: ByteArray = byteArrayOf() + } - /** - * Full save data containing friend list, last seen DHT nodes, name, and all other information - * contained within a Tox instance. - */ - final data class ToxSave(override val data: ByteArray) : Type { - override val kind: ToxSavedataType = ToxSavedataType.TOX_SAVE - } + /** + * Full save data containing friend list, last seen DHT nodes, name, and all other information + * contained within a Tox instance. + */ + final data class ToxSave(override val data: ByteArray) : Type { + override val kind: ToxSavedataType = ToxSavedataType.TOX_SAVE + } - /** - * Minimal save data with just the secret key. The public key can be derived from it. Saving this - * secret key, the friend list, name, and noSpam value is sufficient to restore the observable - * behaviour of a Tox instance without the full save data in [[ToxSave]]. - */ - final data class SecretKey(private val key: ToxSecretKey) : Type { - override val kind: ToxSavedataType = ToxSavedataType.SECRET_KEY - override val data: ByteArray = key.value - } + /** + * Minimal save data with just the secret key. The public key can be derived from it. Saving this + * secret key, the friend list, name, and noSpam value is sufficient to restore the observable + * behaviour of a Tox instance without the full save data in [[ToxSave]]. + */ + final data class SecretKey(private val key: ToxSecretKey) : Type { + override val kind: ToxSavedataType = ToxSavedataType.SECRET_KEY + override val data: ByteArray = key.value + } } diff --git a/lib/src/main/java/im/tox/tox4j/core/options/ToxOptions.kt b/lib/src/main/java/im/tox/tox4j/core/options/ToxOptions.kt index ea8ee9c50..c013df448 100644 --- a/lib/src/main/java/im/tox/tox4j/core/options/ToxOptions.kt +++ b/lib/src/main/java/im/tox/tox4j/core/options/ToxOptions.kt @@ -37,9 +37,9 @@ final data class ToxOptions( val udpEnabled: Boolean = true, val localDiscoveryEnabled: Boolean = true, val proxy: ProxyOptions.Type = ProxyOptions.None, - val startPort: UShort = ToxCoreConstants.DefaultStartPort, - val endPort: UShort = ToxCoreConstants.DefaultEndPort, - val tcpPort: UShort = ToxCoreConstants.DefaultTcpPort, + val startPort: UShort = ToxCoreConstants.DEFAULT_START_PORT, + val endPort: UShort = ToxCoreConstants.DEFAULT_END_PORT, + val tcpPort: UShort = ToxCoreConstants.DEFAULT_TCP_PORT, val saveData: SaveDataOptions.Type = SaveDataOptions.None, val fatalErrors: Boolean = true, ) diff --git a/lib/src/main/java/im/tox/tox4j/crypto/ToxCrypto.kt b/lib/src/main/java/im/tox/tox4j/crypto/ToxCrypto.kt index 6ecb28c1e..0162e7c35 100644 --- a/lib/src/main/java/im/tox/tox4j/crypto/ToxCrypto.kt +++ b/lib/src/main/java/im/tox/tox4j/crypto/ToxCrypto.kt @@ -12,103 +12,114 @@ package im.tox.tox4j.crypto * no way to recover the data. */ interface ToxCrypto { + /** + * Compares two [[PassKey]]s for equality. + * + * @return true if the [[PassKey]]s are equal. + */ + fun passKeyEquals( + a: PassKey, + b: PassKey, + ): Boolean - /** - * Compares two [[PassKey]]s for equality. - * - * @return true if the [[PassKey]]s are equal. - */ - fun passKeyEquals(a: PassKey, b: PassKey): Boolean + /** + * Serialise the [[PassKey]] to a byte sequence. + * + * @return A sequence of bytes making up a [[PassKey]]. + */ + fun passKeyToBytes(passKey: PassKey): List - /** - * Serialise the [[PassKey]] to a byte sequence. - * - * @return A sequence of bytes making up a [[PassKey]]. - */ - fun passKeyToBytes(passKey: PassKey): List + /** + * Deserialise a [[PassKey]] from a byte sequence. + * + * @return [[Some]]([[PassKey]]) if the key was valid, [[None]] otherwise. + */ + fun passKeyFromBytes(bytes: List): PassKey? - /** - * Deserialise a [[PassKey]] from a byte sequence. - * - * @return [[Some]]([[PassKey]]) if the key was valid, [[None]] otherwise. - */ - fun passKeyFromBytes(bytes: List): PassKey? + /** + * Generates a secret symmetric key from the given passphrase. + * + * Be sure to not compromise the key! Only keep it in memory, do not write to disk. The key should + * only be used with the other functions in this module, as it includes a salt. + * + * Note that this function is not deterministic; to derive the same key from a password, you also + * must know the random salt that was used. See below. + * + * @param passphrase A non-empty byte array containing the passphrase. + * @return the generated symmetric key. + * @throws ToxKeyDerivationException + */ + fun passKeyDerive(passphrase: ByteArray): PassKey - /** - * Generates a secret symmetric key from the given passphrase. - * - * Be sure to not compromise the key! Only keep it in memory, do not write to disk. The key should - * only be used with the other functions in this module, as it includes a salt. - * - * Note that this function is not deterministic; to derive the same key from a password, you also - * must know the random salt that was used. See below. - * - * @param passphrase A non-empty byte array containing the passphrase. - * @return the generated symmetric key. - */ - // @throws[ToxKeyDerivationException] - fun passKeyDerive(passphrase: ByteArray): PassKey + /** + * Same as above, except use the given salt for deterministic key derivation. + * + * @param passphrase A non-empty byte array containing the passphrase. + * @param salt Array of size [[ToxCryptoConstants.SALT_LENGTH]]. + * @throws ToxKeyDerivationException + */ + fun passKeyDeriveWithSalt( + passphrase: ByteArray, + salt: ByteArray, + ): PassKey - /** - * Same as above, except use the given salt for deterministic key derivation. - * - * @param passphrase A non-empty byte array containing the passphrase. - * @param salt Array of size [[ToxCryptoConstants.SaltLength]]. - */ - // @throws[ToxKeyDerivationException] - fun passKeyDeriveWithSalt(passphrase: ByteArray, salt: ByteArray): PassKey + /** + * This retrieves the salt used to encrypt the given data, which can then be passed to + * [[passKeyDeriveWithSalt]] to produce the same key as was previously used. Any encrypted data + * with this module can be used as input. + * + * Success does not say anything about the validity of the data, only that data of the appropriate + * size was copied. + * + * @return the salt, or an empty array if the magic number did not match. + * @throws ToxGetSaltException + */ + fun getSalt(data: ByteArray): ByteArray - /** - * This retrieves the salt used to encrypt the given data, which can then be passed to - * [[passKeyDeriveWithSalt]] to produce the same key as was previously used. Any encrypted data - * with this module can be used as input. - * - * Success does not say anything about the validity of the data, only that data of the appropriate - * size was copied. - * - * @return the salt, or an empty array if the magic number did not match. - */ - // @throws[ToxGetSaltException] - fun getSalt(data: ByteArray): ByteArray + // Now come the functions that are analogous to the part 2 functions. - /* Now come the functions that are analogous to the part 2 functions. */ + /** + * Encrypt arbitrary data with a key produced by [[passKeyDerive]] or [[passKeyDeriveWithSalt]]. + * + * The output array will be [[ToxCryptoConstants.ENCRYPTION_EXTRA_LENGTH]] bytes longer than the + * input array. + * + * The result will be different on each call. + * + * @return the encrypted output array. + * @throws ToxEncryptionException + */ + fun encrypt( + data: ByteArray, + passKey: PassKey, + ): ByteArray - /** - * Encrypt arbitrary data with a key produced by [[passKeyDerive]] or [[passKeyDeriveWithSalt]]. - * - * The output array will be [[ToxCryptoConstants.EncryptionExtraLength]] bytes longer than the - * input array. - * - * The result will be different on each call. - * - * @return the encrypted output array. - */ - // @throws[ToxEncryptionException] - fun encrypt(data: ByteArray, passKey: PassKey): ByteArray + /** + * This is the inverse of [[encrypt]], also using only keys produced by [[passKeyDerive]]. + * + * The output data has size data_length - [[ToxCryptoConstants.ENCRYPTION_EXTRA_LENGTH]]. + * + * @return the decrypted output array. + * @throws ToxDecryptionException + */ + fun decrypt( + data: ByteArray, + passKey: PassKey, + ): ByteArray - /** - * This is the inverse of [[encrypt]], also using only keys produced by [[passKeyDerive]]. - * - * The output data has size data_length - [[ToxCryptoConstants.EncryptionExtraLength]]. - * - * @return the decrypted output array. - */ - // @throws[ToxDecryptionException] - fun decrypt(data: ByteArray, passKey: PassKey): ByteArray + /** Determines whether or not the given data is encrypted (by checking the magic number) */ + fun isDataEncrypted(data: ByteArray): Boolean - /** Determines whether or not the given data is encrypted (by checking the magic number) */ - fun isDataEncrypted(data: ByteArray): Boolean - - /** - * Generates a cryptographic hash of the given data. - * - * This function may be used by clients for any purpose, but is provided primarily for validating - * cached avatars. This use is highly recommended to avoid unnecessary avatar updates. - * - * This function is a wrapper to internal message-digest functions. - * - * @param data Data to be hashed. - * @return hash of the data. - */ - fun hash(data: ByteArray): ByteArray + /** + * Generates a cryptographic hash of the given data. + * + * This function may be used by clients for any purpose, but is provided primarily for validating + * cached avatars. This use is highly recommended to avoid unnecessary avatar updates. + * + * This function is a wrapper to internal message-digest functions. + * + * @param data Data to be hashed. + * @return hash of the data. + */ + fun hash(data: ByteArray): ByteArray } diff --git a/lib/src/main/java/im/tox/tox4j/crypto/ToxCryptoConstants.kt b/lib/src/main/java/im/tox/tox4j/crypto/ToxCryptoConstants.kt index e9f2530f5..8450cb7a0 100644 --- a/lib/src/main/java/im/tox/tox4j/crypto/ToxCryptoConstants.kt +++ b/lib/src/main/java/im/tox/tox4j/crypto/ToxCryptoConstants.kt @@ -1,27 +1,26 @@ package im.tox.tox4j.crypto object ToxCryptoConstants { + /** Length of salt in bytes. */ + const val SALT_LENGTH = 32 - /** Length of salt in bytes. */ - const val SaltLength = 32 + /** + * The number of bytes in a serialised [[ToxCrypto.PassKey]] without salt. The serialised size is + * [[KEY_LENGTH]] + [[SALT_LENGTH]]. + */ + const val KEY_LENGTH = 32 - /** - * The number of bytes in a serialised [[ToxCrypto.PassKey]] without salt. The serialised size is - * [[KeyLength]] + [[SaltLength]]. - */ - const val KeyLength = 32 + /** Number of bytes added to any encrypted data. */ + const val ENCRYPTION_EXTRA_LENGTH = 80 - /** Number of bytes added to any encrypted data. */ - const val EncryptionExtraLength = 80 + /** The number of bytes in a hash generated by tox_hash. */ + const val HASH_LENGTH = 32 - /** The number of bytes in a hash generated by tox_hash. */ - const val HashLength = 32 + const val PUBLIC_KEY_LENGTH = 32 + const val SECRET_KEY_LENGTH = 32 + const val SHARED_KEY_LENGTH = 32 + const val NONCE_LENGTH = 24 - const val PublicKeyLength = 32 - const val SecretKeyLength = 32 - const val SharedKeyLength = 32 - const val NonceLength = 24 - - const val ZeroBytes = 32 - const val BoxZeroBytes = 16 + const val ZERO_BYTES = 32 + const val BOX_ZERO_BYTES = 16 } diff --git a/lib/src/main/java/im/tox/tox4j/exceptions/ToxException.kt b/lib/src/main/java/im/tox/tox4j/exceptions/ToxException.kt index e0d7c5ec9..a6b9f4c6e 100644 --- a/lib/src/main/java/im/tox/tox4j/exceptions/ToxException.kt +++ b/lib/src/main/java/im/tox/tox4j/exceptions/ToxException.kt @@ -2,11 +2,10 @@ package im.tox.tox4j.exceptions abstract class ToxException constructor(val code: Enum<*>, private val extraMessage: String) : Exception(extraMessage) { - - final override val message: String - get() = - when (extraMessage) { - "" -> "Error code: " + code.name - else -> extraMessage + ", error code: " + code.name - } -} + final override val message: String + get() = + when (extraMessage) { + "" -> "Error code: " + code.name + else -> extraMessage + ", error code: " + code.name + } + } diff --git a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvEventDispatch.kt b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvEventDispatch.kt index fe96d4197..3222e1dae 100644 --- a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvEventDispatch.kt +++ b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvEventDispatch.kt @@ -25,184 +25,225 @@ import im.tox.tox4j.core.data.ToxFriendNumber import java.util.EnumSet object ToxAvEventDispatch { - - fun convert(channels: Int): AudioChannels = - when (channels) { - 1 -> AudioChannels.Mono - 2 -> AudioChannels.Stereo - else -> AudioChannels.Stereo - } - - fun convert(kind: CallState.Kind): ToxavFriendCallState = - when (kind) { - CallState.Kind.ERROR -> ToxavFriendCallState.ERROR - CallState.Kind.FINISHED -> ToxavFriendCallState.FINISHED - CallState.Kind.SENDING_A -> ToxavFriendCallState.SENDING_A - CallState.Kind.SENDING_V -> ToxavFriendCallState.SENDING_V - CallState.Kind.ACCEPTING_A -> ToxavFriendCallState.ACCEPTING_A - CallState.Kind.ACCEPTING_V -> ToxavFriendCallState.ACCEPTING_V - CallState.Kind.UNRECOGNIZED -> ToxavFriendCallState.ERROR - } - - fun convert(callState: EnumSet): Int = - callState.fold( - 0, - { bitMask, bit -> - val nextMask = - when (bit) { - ToxavFriendCallState.ERROR -> 1 shl 0 - ToxavFriendCallState.FINISHED -> 1 shl 1 - ToxavFriendCallState.SENDING_A -> 1 shl 2 - ToxavFriendCallState.SENDING_V -> 1 shl 3 - ToxavFriendCallState.ACCEPTING_A -> 1 shl 4 - ToxavFriendCallState.ACCEPTING_V -> 1 shl 5 - null -> 0 - } - bitMask or nextMask - }) - - private fun dispatchCall(handler: CallCallback, call: List, state: S): S = - call.fold( - state, - { next, ev -> - handler.call( - ToxFriendNumber(ev.getFriendNumber()), - ev.getAudioEnabled(), - ev.getVideoEnabled(), - next) - }) - - private fun dispatchCallState( - handler: CallStateCallback, - callState: List, - state: S - ): S = - callState.fold( - state, - { next, ev -> - val bits = ev.getCallStateList().map { convert(it) } - handler.callState( - ToxFriendNumber(ev.getFriendNumber()), - EnumSet.of(bits[0], *bits.drop(1).toTypedArray()), - next) - }) - - private fun dispatchAudioBitRate( - handler: AudioBitRateCallback, - audioBitRate: List, - state: S - ): S = - audioBitRate.fold( - state, - { next, ev -> - handler.audioBitRate( - ToxFriendNumber(ev.getFriendNumber()), BitRate(ev.getAudioBitRate()), next) - }) - - private fun dispatchVideoBitRate( - handler: VideoBitRateCallback, - videoBitRate: List, - state: S - ): S = - videoBitRate.fold( - state, - { next, ev -> - handler.videoBitRate( - ToxFriendNumber(ev.getFriendNumber()), BitRate(ev.getVideoBitRate()), next) - }) - - private fun toShortArray(bytes: ByteString): ShortArray { - val shortBuffer = bytes.asReadOnlyByteBuffer().asShortBuffer() - val shortArray = ShortArray(shortBuffer.capacity()) - shortBuffer.get(shortArray) - return shortArray - } - - private fun dispatchAudioReceiveFrame( - handler: AudioReceiveFrameCallback, - audioReceiveFrame: List, - state: S - ): S = - audioReceiveFrame.fold( - state, - { next, ev -> - handler.audioReceiveFrame( - ToxFriendNumber(ev.getFriendNumber()), - toShortArray(ev.getPcm()), - convert(ev.getChannels()), - SamplingRate.values().filter { it.value == ev.getSamplingRate() }[0], - next) - }) - - private fun convert( - arrays: Triple?, - y: ByteString, - u: ByteString, - v: ByteString - ): Triple = - if (arrays == null) { - Triple(y.toByteArray(), u.toByteArray(), v.toByteArray()) - } else { - y.copyTo(arrays.first, 0) - u.copyTo(arrays.second, 0) - v.copyTo(arrays.third, 0) - arrays - } - - private fun dispatchVideoReceiveFrame( - handler: VideoReceiveFrameCallback, - videoReceiveFrame: List, - state: S - ): S = - videoReceiveFrame.fold( - state, - { next, ev -> - val w = Width(ev.getWidth()) - val h = Height(ev.getHeight()) - val (yArray, uArray, vArray) = - convert( - handler.videoFrameCachedYUV( - h, ev.getYStride(), ev.getUStride(), ev.getVStride()), - ev.getY(), - ev.getU(), - ev.getV()) - - handler.videoReceiveFrame( - ToxFriendNumber(ev.getFriendNumber()), - w, - h, - yArray, - uArray, - vArray, - ev.getYStride(), - ev.getUStride(), - ev.getVStride(), - next) - }) - - private fun dispatchEvents(handler: ToxAvEventListener, events: AvEvents, state: S): S = - dispatchCall( - handler, - events.getCallList(), - dispatchCallState( - handler, - events.getCallStateList(), - dispatchAudioBitRate( - handler, - events.getAudioBitRateList(), - dispatchVideoBitRate( - handler, - events.getVideoBitRateList(), - dispatchAudioReceiveFrame( - handler, - events.getAudioReceiveFrameList(), - dispatchVideoReceiveFrame( - handler, events.getVideoReceiveFrameList(), state)))))) - - fun dispatch(handler: ToxAvEventListener, eventData: ByteArray?, state: S): S = - if (eventData == null) { - state - } else { - dispatchEvents(handler, AvEvents.parseFrom(eventData), state) - } + fun convert(channels: Int): AudioChannels = + when (channels) { + 1 -> AudioChannels.Mono + 2 -> AudioChannels.Stereo + else -> AudioChannels.Stereo + } + + fun convert(kind: CallState.Kind): ToxavFriendCallState = + when (kind) { + CallState.Kind.ERROR -> ToxavFriendCallState.ERROR + CallState.Kind.FINISHED -> ToxavFriendCallState.FINISHED + CallState.Kind.SENDING_A -> ToxavFriendCallState.SENDING_A + CallState.Kind.SENDING_V -> ToxavFriendCallState.SENDING_V + CallState.Kind.ACCEPTING_A -> ToxavFriendCallState.ACCEPTING_A + CallState.Kind.ACCEPTING_V -> ToxavFriendCallState.ACCEPTING_V + CallState.Kind.UNRECOGNIZED -> ToxavFriendCallState.ERROR + } + + fun convert(callState: EnumSet): Int = + callState.fold( + 0, + { bitMask, bit -> + val nextMask = + when (bit) { + ToxavFriendCallState.ERROR -> 1 shl 0 + ToxavFriendCallState.FINISHED -> 1 shl 1 + ToxavFriendCallState.SENDING_A -> 1 shl 2 + ToxavFriendCallState.SENDING_V -> 1 shl 3 + ToxavFriendCallState.ACCEPTING_A -> 1 shl 4 + ToxavFriendCallState.ACCEPTING_V -> 1 shl 5 + null -> 0 + } + bitMask or nextMask + }, + ) + + private fun dispatchCall( + handler: CallCallback, + call: List, + state: S, + ): S = + call.fold( + state, + { next, ev -> + handler.call( + ToxFriendNumber(ev.getFriendNumber()), + ev.getAudioEnabled(), + ev.getVideoEnabled(), + next, + ) + }, + ) + + private fun dispatchCallState( + handler: CallStateCallback, + callState: List, + state: S, + ): S = + callState.fold( + state, + { next, ev -> + val bits = ev.getCallStateList().map { convert(it) } + handler.callState( + ToxFriendNumber(ev.getFriendNumber()), + EnumSet.of(bits[0], *bits.drop(1).toTypedArray()), + next, + ) + }, + ) + + private fun dispatchAudioBitRate( + handler: AudioBitRateCallback, + audioBitRate: List, + state: S, + ): S = + audioBitRate.fold( + state, + { next, ev -> + handler.audioBitRate( + ToxFriendNumber(ev.getFriendNumber()), + BitRate(ev.getAudioBitRate()), + next, + ) + }, + ) + + private fun dispatchVideoBitRate( + handler: VideoBitRateCallback, + videoBitRate: List, + state: S, + ): S = + videoBitRate.fold( + state, + { next, ev -> + handler.videoBitRate( + ToxFriendNumber(ev.getFriendNumber()), + BitRate(ev.getVideoBitRate()), + next, + ) + }, + ) + + private fun toShortArray(bytes: ByteString): ShortArray { + val shortBuffer = bytes.asReadOnlyByteBuffer().asShortBuffer() + val shortArray = ShortArray(shortBuffer.capacity()) + shortBuffer.get(shortArray) + return shortArray + } + + private fun dispatchAudioReceiveFrame( + handler: AudioReceiveFrameCallback, + audioReceiveFrame: List, + state: S, + ): S = + audioReceiveFrame.fold( + state, + { next, ev -> + handler.audioReceiveFrame( + ToxFriendNumber(ev.getFriendNumber()), + toShortArray(ev.getPcm()), + convert(ev.getChannels()), + SamplingRate.values().filter { it.value == ev.getSamplingRate() }[0], + next, + ) + }, + ) + + private fun convert( + arrays: Triple?, + y: ByteString, + u: ByteString, + v: ByteString, + ): Triple = + if (arrays == null) { + Triple(y.toByteArray(), u.toByteArray(), v.toByteArray()) + } else { + y.copyTo(arrays.first, 0) + u.copyTo(arrays.second, 0) + v.copyTo(arrays.third, 0) + arrays + } + + private fun dispatchVideoReceiveFrame( + handler: VideoReceiveFrameCallback, + videoReceiveFrame: List, + state: S, + ): S = + videoReceiveFrame.fold( + state, + { next, ev -> + val w = Width(ev.getWidth()) + val h = Height(ev.getHeight()) + val (yArray, uArray, vArray) = + convert( + handler.videoFrameCachedYUV( + h, + ev.getYStride(), + ev.getUStride(), + ev.getVStride(), + ), + ev.getY(), + ev.getU(), + ev.getV(), + ) + + handler.videoReceiveFrame( + ToxFriendNumber(ev.getFriendNumber()), + w, + h, + yArray, + uArray, + vArray, + ev.getYStride(), + ev.getUStride(), + ev.getVStride(), + next, + ) + }, + ) + + private fun dispatchEvents( + handler: ToxAvEventListener, + events: AvEvents, + state: S, + ): S = + dispatchCall( + handler, + events.getCallList(), + dispatchCallState( + handler, + events.getCallStateList(), + dispatchAudioBitRate( + handler, + events.getAudioBitRateList(), + dispatchVideoBitRate( + handler, + events.getVideoBitRateList(), + dispatchAudioReceiveFrame( + handler, + events.getAudioReceiveFrameList(), + dispatchVideoReceiveFrame( + handler, + events.getVideoReceiveFrameList(), + state, + ), + ), + ), + ), + ), + ) + + fun dispatch( + handler: ToxAvEventListener, + eventData: ByteArray?, + state: S, + ): S = + if (eventData == null) { + state + } else { + dispatchEvents(handler, AvEvents.parseFrom(eventData), state) + } } diff --git a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvImpl.kt b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvImpl.kt index 2ac2d1a71..c02d919d8 100644 --- a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvImpl.kt +++ b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxAvImpl.kt @@ -15,91 +15,101 @@ import im.tox.tox4j.core.data.ToxFriendNumber * Initialise an A/V session for the existing Tox instance. * * @param tox An instance of the C-backed ToxCore implementation. + * @throws ToxavNewException If there was already an A/V session. */ -// @throws[ToxavNewException]("If there was already an A/V session.") final class ToxAvImpl(private val tox: ToxCoreImpl) : ToxAv { + internal val instanceNumber = ToxAvJni.toxavNew(tox.instanceNumber) - internal val instanceNumber = ToxAvJni.toxavNew(tox.instanceNumber) + override fun create(tox: ToxCore): ToxAv = + try { + ToxAvImpl(tox as ToxCoreImpl) + } catch (_: ClassCastException) { + throw ToxavNewException( + ToxavNewException.Code.INCOMPATIBLE, + tox::class.java.getCanonicalName(), + ) + } - override fun create(tox: ToxCore): ToxAv = - try { - ToxAvImpl(tox as ToxCoreImpl) - } catch (_: ClassCastException) { - throw ToxavNewException( - ToxavNewException.Code.INCOMPATIBLE, tox::class.java.getCanonicalName()) - } + override fun close(): Unit = ToxAvJni.toxavKill(instanceNumber) - override fun close(): Unit = ToxAvJni.toxavKill(instanceNumber) + protected fun finalize(): Unit = ToxAvJni.toxavFinalize(instanceNumber) - protected fun finalize(): Unit = ToxAvJni.toxavFinalize(instanceNumber) + override fun iterate( + handler: ToxAvEventListener, + state: S, + ): S = ToxAvEventDispatch.dispatch(handler, ToxAvJni.toxavIterate(instanceNumber), state) - override fun iterate(handler: ToxAvEventListener, state: S): S = - ToxAvEventDispatch.dispatch(handler, ToxAvJni.toxavIterate(instanceNumber), state) + override val iterationInterval: Int + get() = ToxAvJni.toxavIterationInterval(instanceNumber) - override val iterationInterval: Int - get() = ToxAvJni.toxavIterationInterval(instanceNumber) + // @throws[ToxavCallException] + override fun call( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + videoBitRate: BitRate, + ): Unit = + ToxAvJni.toxavCall( + instanceNumber, + friendNumber.value, + audioBitRate.value, + videoBitRate.value, + ) - // @throws[ToxavCallException] - override fun call( - friendNumber: ToxFriendNumber, - audioBitRate: BitRate, - videoBitRate: BitRate - ): Unit = - ToxAvJni.toxavCall( - instanceNumber, - friendNumber.value, - audioBitRate.value, - videoBitRate.value, - ) + // @throws[ToxavAnswerException] + override fun answer( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + videoBitRate: BitRate, + ): Unit = + ToxAvJni.toxavAnswer( + instanceNumber, + friendNumber.value, + audioBitRate.value, + videoBitRate.value, + ) - // @throws[ToxavAnswerException] - override fun answer( - friendNumber: ToxFriendNumber, - audioBitRate: BitRate, - videoBitRate: BitRate - ): Unit = - ToxAvJni.toxavAnswer( - instanceNumber, - friendNumber.value, - audioBitRate.value, - videoBitRate.value, - ) + // @throws[ToxavCallControlException] + override fun callControl( + friendNumber: ToxFriendNumber, + control: ToxavCallControl, + ): Unit = ToxAvJni.toxavCallControl(instanceNumber, friendNumber.value, control.ordinal) - // @throws[ToxavCallControlException] - override fun callControl(friendNumber: ToxFriendNumber, control: ToxavCallControl): Unit = - ToxAvJni.toxavCallControl(instanceNumber, friendNumber.value, control.ordinal) + // @throws[ToxavBitRateSetException] + override fun setAudioBitRate( + friendNumber: ToxFriendNumber, + audioBitRate: BitRate, + ): Unit = ToxAvJni.toxavAudioSetBitRate(instanceNumber, friendNumber.value, audioBitRate.value) - // @throws[ToxavBitRateSetException] - override fun setAudioBitRate(friendNumber: ToxFriendNumber, audioBitRate: BitRate): Unit = - ToxAvJni.toxavAudioSetBitRate(instanceNumber, friendNumber.value, audioBitRate.value) + // @throws[ToxavBitRateSetException] + override fun setVideoBitRate( + friendNumber: ToxFriendNumber, + videoBitRate: BitRate, + ): Unit = ToxAvJni.toxavVideoSetBitRate(instanceNumber, friendNumber.value, videoBitRate.value) - // @throws[ToxavBitRateSetException] - override fun setVideoBitRate(friendNumber: ToxFriendNumber, videoBitRate: BitRate): Unit = - ToxAvJni.toxavVideoSetBitRate(instanceNumber, friendNumber.value, videoBitRate.value) + // @throws[ToxavSendFrameException] + override fun audioSendFrame( + friendNumber: ToxFriendNumber, + pcm: ShortArray, + sampleCount: SampleCount, + channels: AudioChannels, + samplingRate: SamplingRate, + ): Unit = + ToxAvJni.toxavAudioSendFrame( + instanceNumber, + friendNumber.value, + pcm, + sampleCount.value, + channels.value, + samplingRate.value, + ) - // @throws[ToxavSendFrameException] - override fun audioSendFrame( - friendNumber: ToxFriendNumber, - pcm: ShortArray, - sampleCount: SampleCount, - channels: AudioChannels, - samplingRate: SamplingRate - ): Unit = - ToxAvJni.toxavAudioSendFrame( - instanceNumber, - friendNumber.value, - pcm, - sampleCount.value, - channels.value, - samplingRate.value) - - // @throws[ToxavSendFrameException] - override fun videoSendFrame( - friendNumber: ToxFriendNumber, - width: Int, - height: Int, - y: ByteArray, - u: ByteArray, - v: ByteArray - ): Unit = ToxAvJni.toxavVideoSendFrame(instanceNumber, friendNumber.value, width, height, y, u, v) + // @throws[ToxavSendFrameException] + override fun videoSendFrame( + friendNumber: ToxFriendNumber, + width: Int, + height: Int, + y: ByteArray, + u: ByteArray, + v: ByteArray, + ): Unit = ToxAvJni.toxavVideoSendFrame(instanceNumber, friendNumber.value, width, height, y, u, v) } diff --git a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreEventDispatch.kt b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreEventDispatch.kt index f9c28e221..b8c56e354 100644 --- a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreEventDispatch.kt +++ b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreEventDispatch.kt @@ -36,309 +36,361 @@ import im.tox.tox4j.core.proto.SelfConnectionStatus import im.tox.tox4j.core.proto.UserStatus object ToxCoreEventDispatch { + fun convert(status: Connection.Type): ToxConnection = + when (status) { + Connection.Type.NONE -> ToxConnection.NONE + Connection.Type.TCP -> ToxConnection.TCP + Connection.Type.UDP -> ToxConnection.UDP + Connection.Type.UNRECOGNIZED -> ToxConnection.NONE + } - fun convert(status: Connection.Type): ToxConnection = - when (status) { - Connection.Type.NONE -> ToxConnection.NONE - Connection.Type.TCP -> ToxConnection.TCP - Connection.Type.UDP -> ToxConnection.UDP - Connection.Type.UNRECOGNIZED -> ToxConnection.NONE - } + fun convert(status: UserStatus.Type): ToxUserStatus = + when (status) { + UserStatus.Type.NONE -> ToxUserStatus.NONE + UserStatus.Type.AWAY -> ToxUserStatus.AWAY + UserStatus.Type.BUSY -> ToxUserStatus.BUSY + UserStatus.Type.UNRECOGNIZED -> ToxUserStatus.NONE + } - fun convert(status: UserStatus.Type): ToxUserStatus = - when (status) { - UserStatus.Type.NONE -> ToxUserStatus.NONE - UserStatus.Type.AWAY -> ToxUserStatus.AWAY - UserStatus.Type.BUSY -> ToxUserStatus.BUSY - UserStatus.Type.UNRECOGNIZED -> ToxUserStatus.NONE - } + fun convert(status: ToxUserStatus): UserStatus.Type = + when (status) { + ToxUserStatus.NONE -> UserStatus.Type.NONE + ToxUserStatus.AWAY -> UserStatus.Type.AWAY + ToxUserStatus.BUSY -> UserStatus.Type.BUSY + } - fun convert(status: ToxUserStatus): UserStatus.Type = - when (status) { - ToxUserStatus.NONE -> UserStatus.Type.NONE - ToxUserStatus.AWAY -> UserStatus.Type.AWAY - ToxUserStatus.BUSY -> UserStatus.Type.BUSY - } + fun convert(control: FileControl.Type): ToxFileControl = + when (control) { + FileControl.Type.RESUME -> ToxFileControl.RESUME + FileControl.Type.PAUSE -> ToxFileControl.PAUSE + FileControl.Type.CANCEL -> ToxFileControl.CANCEL + FileControl.Type.UNRECOGNIZED -> ToxFileControl.CANCEL + } - fun convert(control: FileControl.Type): ToxFileControl = - when (control) { - FileControl.Type.RESUME -> ToxFileControl.RESUME - FileControl.Type.PAUSE -> ToxFileControl.PAUSE - FileControl.Type.CANCEL -> ToxFileControl.CANCEL - FileControl.Type.UNRECOGNIZED -> ToxFileControl.CANCEL - } + fun convert(messageType: MessageType.Type): ToxMessageType = + when (messageType) { + MessageType.Type.NORMAL -> ToxMessageType.NORMAL + MessageType.Type.ACTION -> ToxMessageType.ACTION + MessageType.Type.UNRECOGNIZED -> ToxMessageType.NORMAL + } - fun convert(messageType: MessageType.Type): ToxMessageType = - when (messageType) { - MessageType.Type.NORMAL -> ToxMessageType.NORMAL - MessageType.Type.ACTION -> ToxMessageType.ACTION - MessageType.Type.UNRECOGNIZED -> ToxMessageType.NORMAL - } + private fun dispatchSelfConnectionStatus( + handler: ToxCoreEventListener, + selfConnectionStatus: List, + state: S, + ): S = + selfConnectionStatus.fold( + state, + { next, ev -> handler.selfConnectionStatus(convert(ev.getConnectionStatus()), next) }, + ) - private fun dispatchSelfConnectionStatus( - handler: ToxCoreEventListener, - selfConnectionStatus: List, - state: S - ): S = - selfConnectionStatus.fold( - state, - { next, ev -> handler.selfConnectionStatus(convert(ev.getConnectionStatus()), next) }) + private fun dispatchFriendName( + handler: ToxCoreEventListener, + friendName: List, + state: S, + ): S = + friendName.fold( + state, + { next, ev -> + handler.friendName( + ToxFriendNumber(ev.getFriendNumber()), + ToxNickname(ev.getName().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendName( - handler: ToxCoreEventListener, - friendName: List, - state: S - ): S = - friendName.fold( - state, - { next, ev -> - handler.friendName( - ToxFriendNumber(ev.getFriendNumber()), - ToxNickname(ev.getName().toByteArray()), - next) - }) + private fun dispatchFriendStatusMessage( + handler: ToxCoreEventListener, + friendStatusMessage: List, + state: S, + ): S = + friendStatusMessage.fold( + state, + { next, ev -> + handler.friendStatusMessage( + ToxFriendNumber(ev.getFriendNumber()), + ToxStatusMessage(ev.getMessage().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendStatusMessage( - handler: ToxCoreEventListener, - friendStatusMessage: List, - state: S - ): S = - friendStatusMessage.fold( - state, - { next, ev -> - handler.friendStatusMessage( - ToxFriendNumber(ev.getFriendNumber()), - ToxStatusMessage(ev.getMessage().toByteArray()), - next) - }) + private fun dispatchFriendStatus( + handler: ToxCoreEventListener, + friendStatus: List, + state: S, + ): S = + friendStatus.fold( + state, + { next, ev -> + handler.friendStatus( + ToxFriendNumber(ev.getFriendNumber()), + convert(ev.getStatus()), + next, + ) + }, + ) - private fun dispatchFriendStatus( - handler: ToxCoreEventListener, - friendStatus: List, - state: S - ): S = - friendStatus.fold( - state, - { next, ev -> - handler.friendStatus( - ToxFriendNumber(ev.getFriendNumber()), convert(ev.getStatus()), next) - }) + private fun dispatchFriendConnectionStatus( + handler: ToxCoreEventListener, + friendConnectionStatus: List, + state: S, + ): S = + friendConnectionStatus.fold( + state, + { next, ev -> + handler.friendConnectionStatus( + ToxFriendNumber(ev.getFriendNumber()), + convert(ev.getConnectionStatus()), + next, + ) + }, + ) - private fun dispatchFriendConnectionStatus( - handler: ToxCoreEventListener, - friendConnectionStatus: List, - state: S - ): S = - friendConnectionStatus.fold( - state, - { next, ev -> - handler.friendConnectionStatus( - ToxFriendNumber(ev.getFriendNumber()), convert(ev.getConnectionStatus()), next) - }) + private fun dispatchFriendTyping( + handler: ToxCoreEventListener, + friendTyping: List, + state: S, + ): S = + friendTyping.fold( + state, + { next, ev -> + handler.friendTyping(ToxFriendNumber(ev.getFriendNumber()), ev.getIsTyping(), next) + }, + ) - private fun dispatchFriendTyping( - handler: ToxCoreEventListener, - friendTyping: List, - state: S - ): S = - friendTyping.fold( - state, - { next, ev -> - handler.friendTyping(ToxFriendNumber(ev.getFriendNumber()), ev.getIsTyping(), next) - }) + private fun dispatchFriendReadReceipt( + handler: ToxCoreEventListener, + friendReadReceipt: List, + state: S, + ): S = + friendReadReceipt.fold( + state, + { next, ev -> + handler.friendReadReceipt( + ToxFriendNumber(ev.getFriendNumber()), + ev.getMessageId(), + next, + ) + }, + ) - private fun dispatchFriendReadReceipt( - handler: ToxCoreEventListener, - friendReadReceipt: List, - state: S - ): S = - friendReadReceipt.fold( - state, - { next, ev -> - handler.friendReadReceipt( - ToxFriendNumber(ev.getFriendNumber()), ev.getMessageId(), next) - }) + private fun dispatchFriendRequest( + handler: ToxCoreEventListener, + friendRequest: List, + state: S, + ): S = + friendRequest.fold( + state, + { next, ev -> + handler.friendRequest( + ToxPublicKey(ev.getPublicKey().toByteArray()), + ev.getTimeDelta(), + ToxFriendRequestMessage(ev.getMessage().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendRequest( - handler: ToxCoreEventListener, - friendRequest: List, - state: S - ): S = - friendRequest.fold( - state, - { next, ev -> - handler.friendRequest( - ToxPublicKey(ev.getPublicKey().toByteArray()), - ev.getTimeDelta(), - ToxFriendRequestMessage(ev.getMessage().toByteArray()), - next) - }) + private fun dispatchFriendMessage( + handler: ToxCoreEventListener, + friendMessage: List, + state: S, + ): S = + friendMessage.fold( + state, + { next, ev -> + handler.friendMessage( + ToxFriendNumber(ev.getFriendNumber()), + convert(ev.getType()), + ev.getTimeDelta(), + ToxFriendMessage(ev.getMessage().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendMessage( - handler: ToxCoreEventListener, - friendMessage: List, - state: S - ): S = - friendMessage.fold( - state, - { next, ev -> - handler.friendMessage( - ToxFriendNumber(ev.getFriendNumber()), - convert(ev.getType()), - ev.getTimeDelta(), - ToxFriendMessage(ev.getMessage().toByteArray()), - next) - }) + private fun dispatchFileRecvControl( + handler: ToxCoreEventListener, + fileRecvControl: List, + state: S, + ): S = + fileRecvControl.fold( + state, + { next, ev -> + handler.fileRecvControl( + ToxFriendNumber(ev.getFriendNumber()), + ev.getFileNumber(), + convert(ev.getControl()), + next, + ) + }, + ) - private fun dispatchFileRecvControl( - handler: ToxCoreEventListener, - fileRecvControl: List, - state: S - ): S = - fileRecvControl.fold( - state, - { next, ev -> - handler.fileRecvControl( - ToxFriendNumber(ev.getFriendNumber()), - ev.getFileNumber(), - convert(ev.getControl()), - next) - }) + private fun dispatchFileChunkRequest( + handler: ToxCoreEventListener, + fileChunkRequest: List, + state: S, + ): S = + fileChunkRequest.fold( + state, + { next, ev -> + handler.fileChunkRequest( + ToxFriendNumber(ev.getFriendNumber()), + ev.getFileNumber(), + ev.getPosition(), + ev.getLength(), + next, + ) + }, + ) - private fun dispatchFileChunkRequest( - handler: ToxCoreEventListener, - fileChunkRequest: List, - state: S - ): S = - fileChunkRequest.fold( - state, - { next, ev -> - handler.fileChunkRequest( - ToxFriendNumber(ev.getFriendNumber()), - ev.getFileNumber(), - ev.getPosition(), - ev.getLength(), - next) - }) + private fun dispatchFileRecv( + handler: ToxCoreEventListener, + fileRecv: List, + state: S, + ): S = + fileRecv.fold( + state, + { next, ev -> + handler.fileRecv( + ToxFriendNumber(ev.getFriendNumber()), + ev.getFileNumber(), + ev.getKind(), + ev.getFileSize(), + ToxFilename(ev.getFilename().toByteArray()), + next, + ) + }, + ) - private fun dispatchFileRecv( - handler: ToxCoreEventListener, - fileRecv: List, - state: S - ): S = - fileRecv.fold( - state, - { next, ev -> - handler.fileRecv( - ToxFriendNumber(ev.getFriendNumber()), - ev.getFileNumber(), - ev.getKind(), - ev.getFileSize(), - ToxFilename(ev.getFilename().toByteArray()), - next) - }) + private fun dispatchFileRecvChunk( + handler: ToxCoreEventListener, + fileRecvChunk: List, + state: S, + ): S = + fileRecvChunk.fold( + state, + { next, ev -> + handler.fileRecvChunk( + ToxFriendNumber(ev.getFriendNumber()), + ev.getFileNumber(), + ev.getPosition(), + ev.getData().toByteArray(), + next, + ) + }, + ) - private fun dispatchFileRecvChunk( - handler: ToxCoreEventListener, - fileRecvChunk: List, - state: S - ): S = - fileRecvChunk.fold( - state, - { next, ev -> - handler.fileRecvChunk( - ToxFriendNumber(ev.getFriendNumber()), - ev.getFileNumber(), - ev.getPosition(), - ev.getData().toByteArray(), - next) - }) + private fun dispatchFriendLossyPacket( + handler: ToxCoreEventListener, + friendLossyPacket: List, + state: S, + ): S = + friendLossyPacket.fold( + state, + { next, ev -> + handler.friendLossyPacket( + ToxFriendNumber(ev.getFriendNumber()), + ToxLossyPacket(ev.getData().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendLossyPacket( - handler: ToxCoreEventListener, - friendLossyPacket: List, - state: S - ): S = - friendLossyPacket.fold( - state, - { next, ev -> - handler.friendLossyPacket( - ToxFriendNumber(ev.getFriendNumber()), - ToxLossyPacket(ev.getData().toByteArray()), - next) - }) + private fun dispatchFriendLosslessPacket( + handler: ToxCoreEventListener, + friendLosslessPacket: List, + state: S, + ): S = + friendLosslessPacket.fold( + state, + { next, ev -> + handler.friendLosslessPacket( + ToxFriendNumber(ev.getFriendNumber()), + ToxLosslessPacket(ev.getData().toByteArray()), + next, + ) + }, + ) - private fun dispatchFriendLosslessPacket( - handler: ToxCoreEventListener, - friendLosslessPacket: List, - state: S - ): S = - friendLosslessPacket.fold( - state, - { next, ev -> - handler.friendLosslessPacket( - ToxFriendNumber(ev.getFriendNumber()), - ToxLosslessPacket(ev.getData().toByteArray()), - next) - }) + private fun dispatchEvents( + handler: ToxCoreEventListener, + events: CoreEvents, + state: S, + ): S = + dispatchSelfConnectionStatus( + handler, + events.getSelfConnectionStatusList(), + dispatchFriendName( + handler, + events.getFriendNameList(), + dispatchFriendStatusMessage( + handler, + events.getFriendStatusMessageList(), + dispatchFriendStatus( + handler, + events.getFriendStatusList(), + dispatchFriendConnectionStatus( + handler, + events.getFriendConnectionStatusList(), + dispatchFriendTyping( + handler, + events.getFriendTypingList(), + dispatchFriendReadReceipt( + handler, + events.getFriendReadReceiptList(), + dispatchFriendRequest( + handler, + events.getFriendRequestList(), + dispatchFriendMessage( + handler, + events.getFriendMessageList(), + dispatchFileRecvControl( + handler, + events.getFileRecvControlList(), + dispatchFileChunkRequest( + handler, + events.getFileChunkRequestList(), + dispatchFileRecv( + handler, + events.getFileRecvList(), + dispatchFileRecvChunk( + handler, + events.getFileRecvChunkList(), + dispatchFriendLossyPacket( + handler, + events.getFriendLossyPacketList(), + dispatchFriendLosslessPacket( + handler, + events + .getFriendLosslessPacketList(), + state, + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ) - private fun dispatchEvents( - handler: ToxCoreEventListener, - events: CoreEvents, - state: S - ): S = - dispatchSelfConnectionStatus( - handler, - events.getSelfConnectionStatusList(), - dispatchFriendName( - handler, - events.getFriendNameList(), - dispatchFriendStatusMessage( - handler, - events.getFriendStatusMessageList(), - dispatchFriendStatus( - handler, - events.getFriendStatusList(), - dispatchFriendConnectionStatus( - handler, - events.getFriendConnectionStatusList(), - dispatchFriendTyping( - handler, - events.getFriendTypingList(), - dispatchFriendReadReceipt( - handler, - events.getFriendReadReceiptList(), - dispatchFriendRequest( - handler, - events.getFriendRequestList(), - dispatchFriendMessage( - handler, - events.getFriendMessageList(), - dispatchFileRecvControl( - handler, - events.getFileRecvControlList(), - dispatchFileChunkRequest( - handler, - events.getFileChunkRequestList(), - dispatchFileRecv( - handler, - events.getFileRecvList(), - dispatchFileRecvChunk( - handler, - events.getFileRecvChunkList(), - dispatchFriendLossyPacket( - handler, - events.getFriendLossyPacketList(), - dispatchFriendLosslessPacket( - handler, - events - .getFriendLosslessPacketList(), - state))))))))))))))) - - fun dispatch(handler: ToxCoreEventListener, eventData: ByteArray?, state: S): S = - if (eventData == null) { - state - } else { - dispatchEvents(handler, CoreEvents.parseFrom(eventData), state) - } + fun dispatch( + handler: ToxCoreEventListener, + eventData: ByteArray?, + state: S, + ): S = + if (eventData == null) { + state + } else { + dispatchEvents(handler, CoreEvents.parseFrom(eventData), state) + } } diff --git a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreImpl.kt b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreImpl.kt index 50220a102..7eef106ed 100644 --- a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreImpl.kt +++ b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCoreImpl.kt @@ -28,194 +28,224 @@ import im.tox.tox4j.core.options.ToxOptions * @param options Connection options object with optional save-data. */ final class ToxCoreImpl(val options: ToxOptions) : ToxCore { + /** This field has package visibility for [[ToxAvImpl]]. */ + internal val instanceNumber = + ToxCoreJni.toxNew( + options.ipv6Enabled, + options.udpEnabled, + options.localDiscoveryEnabled, + options.proxy.proxyType.ordinal, + options.proxy.proxyAddress, + options.proxy.proxyPort.toInt(), + options.startPort.toInt(), + options.endPort.toInt(), + options.tcpPort.toInt(), + options.saveData.kind.ordinal, + options.saveData.data, + ) + + override fun load(options: ToxOptions): ToxCoreImpl = ToxCoreImpl(options) + + override fun close(): Unit = ToxCoreJni.toxKill(instanceNumber) + + protected fun finalize() { + close() + ToxCoreJni.toxFinalize(instanceNumber) + } + + override fun bootstrap( + address: String, + port: Port, + publicKey: ToxPublicKey, + ) { + ToxCoreImpl.checkBootstrapArguments(publicKey.value) + ToxCoreJni.toxBootstrap(instanceNumber, address, port.value.toInt(), publicKey.value) + } + + override fun addTcpRelay( + address: String, + port: Port, + publicKey: ToxPublicKey, + ) { + ToxCoreImpl.checkBootstrapArguments(publicKey.value) + ToxCoreJni.toxAddTcpRelay(instanceNumber, address, port.value.toInt(), publicKey.value) + } + + override val getSavedata: ByteArray + get() = ToxCoreJni.toxGetSavedata(instanceNumber) - /** This field has package visibility for [[ToxAvImpl]]. */ - internal val instanceNumber = - ToxCoreJni.toxNew( - options.ipv6Enabled, - options.udpEnabled, - options.localDiscoveryEnabled, - options.proxy.proxyType.ordinal, - options.proxy.proxyAddress, - options.proxy.proxyPort.toInt(), - options.startPort.toInt(), - options.endPort.toInt(), - options.tcpPort.toInt(), - options.saveData.kind.ordinal, - options.saveData.data, - ) + override val getUdpPort: Port + get() = Port(ToxCoreJni.toxSelfGetUdpPort(instanceNumber).toUShort()) - override fun load(options: ToxOptions): ToxCoreImpl = ToxCoreImpl(options) + override val getTcpPort: Port + get() = Port(ToxCoreJni.toxSelfGetTcpPort(instanceNumber).toUShort()) - override fun close(): Unit = ToxCoreJni.toxKill(instanceNumber) + override val getDhtId: ToxPublicKey + get() = ToxPublicKey(ToxCoreJni.toxSelfGetDhtId(instanceNumber)) - protected fun finalize(): Unit { - close() - ToxCoreJni.toxFinalize(instanceNumber) - } + override val iterationInterval: Int + get() = ToxCoreJni.toxIterationInterval(instanceNumber) - override fun bootstrap(address: String, port: Port, publicKey: ToxPublicKey): Unit { - ToxCoreImpl.checkBootstrapArguments(publicKey.value) - ToxCoreJni.toxBootstrap(instanceNumber, address, port.value.toInt(), publicKey.value) - } + override fun iterate( + handler: ToxCoreEventListener, + state: S, + ): S = ToxCoreEventDispatch.dispatch(handler, ToxCoreJni.toxIterate(instanceNumber), state) - override fun addTcpRelay(address: String, port: Port, publicKey: ToxPublicKey): Unit { - ToxCoreImpl.checkBootstrapArguments(publicKey.value) - ToxCoreJni.toxAddTcpRelay(instanceNumber, address, port.value.toInt(), publicKey.value) - } + override val getPublicKey: ToxPublicKey + get() = ToxPublicKey(ToxCoreJni.toxSelfGetPublicKey(instanceNumber)) - override val getSavedata: ByteArray - get() = ToxCoreJni.toxGetSavedata(instanceNumber) + override val getSecretKey: ToxSecretKey + get() = ToxSecretKey(ToxCoreJni.toxSelfGetSecretKey(instanceNumber)) - override val getUdpPort: Port - get() = Port(ToxCoreJni.toxSelfGetUdpPort(instanceNumber).toUShort()) + override fun setNospam(nospam: Int): Unit = ToxCoreJni.toxSelfSetNospam(instanceNumber, nospam) - override val getTcpPort: Port - get() = Port(ToxCoreJni.toxSelfGetTcpPort(instanceNumber).toUShort()) - - override val getDhtId: ToxPublicKey - get() = ToxPublicKey(ToxCoreJni.toxSelfGetDhtId(instanceNumber)) - - override val iterationInterval: Int - get() = ToxCoreJni.toxIterationInterval(instanceNumber) - - override fun iterate(handler: ToxCoreEventListener, state: S): S = - ToxCoreEventDispatch.dispatch(handler, ToxCoreJni.toxIterate(instanceNumber), state) - - override val getPublicKey: ToxPublicKey - get() = ToxPublicKey(ToxCoreJni.toxSelfGetPublicKey(instanceNumber)) - - override val getSecretKey: ToxSecretKey - get() = ToxSecretKey(ToxCoreJni.toxSelfGetSecretKey(instanceNumber)) - - override fun setNospam(nospam: Int): Unit = ToxCoreJni.toxSelfSetNospam(instanceNumber, nospam) - - override val getNospam: Int - get() = ToxCoreJni.toxSelfGetNospam(instanceNumber) - - override val getAddress: ToxFriendAddress - get() = ToxFriendAddress(ToxCoreJni.toxSelfGetAddress(instanceNumber)) - - override fun setName(name: ToxNickname): Unit = - ToxCoreJni.toxSelfSetName(instanceNumber, name.value) - - override val getName: ToxNickname - get() = ToxNickname(ToxCoreJni.toxSelfGetName(instanceNumber)) - - override fun setStatusMessage(message: ToxStatusMessage): Unit { - ToxCoreJni.toxSelfSetStatusMessage(instanceNumber, message.value) - } - - override val getStatusMessage: ToxStatusMessage - get() = ToxStatusMessage(ToxCoreJni.toxSelfGetStatusMessage(instanceNumber)) - - override fun setStatus(status: ToxUserStatus): Unit = - ToxCoreJni.toxSelfSetStatus(instanceNumber, status.ordinal) - - override val getStatus: ToxUserStatus - get() = ToxUserStatus.values()[ToxCoreJni.toxSelfGetStatus(instanceNumber)] - - override fun addFriend( - address: ToxFriendAddress, - message: ToxFriendRequestMessage - ): ToxFriendNumber { - ToxCoreImpl.checkLength("Friend Address", address.value, ToxCoreConstants.AddressSize) - return ToxFriendNumber(ToxCoreJni.toxFriendAdd(instanceNumber, address.value, message.value)) - } - - override fun addFriendNorequest(publicKey: ToxPublicKey): ToxFriendNumber { - ToxCoreImpl.checkLength("Public Key", publicKey.value, ToxCoreConstants.PublicKeySize) - return ToxFriendNumber(ToxCoreJni.toxFriendAddNorequest(instanceNumber, publicKey.value)) - } - - override fun deleteFriend(friendNumber: ToxFriendNumber): Unit = - ToxCoreJni.toxFriendDelete(instanceNumber, friendNumber.value) - - override fun friendByPublicKey(publicKey: ToxPublicKey): ToxFriendNumber = - ToxFriendNumber(ToxCoreJni.toxFriendByPublicKey(instanceNumber, publicKey.value)) - - override fun getFriendPublicKey(friendNumber: ToxFriendNumber): ToxPublicKey = - ToxPublicKey(ToxCoreJni.toxFriendGetPublicKey(instanceNumber, friendNumber.value)) - - override fun friendExists(friendNumber: ToxFriendNumber): Boolean = - ToxCoreJni.toxFriendExists(instanceNumber, friendNumber.value) - - override val getFriendList: IntArray - get() = ToxCoreJni.toxSelfGetFriendList(instanceNumber) + override val getNospam: Int + get() = ToxCoreJni.toxSelfGetNospam(instanceNumber) + + override val getAddress: ToxFriendAddress + get() = ToxFriendAddress(ToxCoreJni.toxSelfGetAddress(instanceNumber)) + + override fun setName(name: ToxNickname): Unit = ToxCoreJni.toxSelfSetName(instanceNumber, name.value) + + override val getName: ToxNickname + get() = ToxNickname(ToxCoreJni.toxSelfGetName(instanceNumber)) + + override fun setStatusMessage(message: ToxStatusMessage) { + ToxCoreJni.toxSelfSetStatusMessage(instanceNumber, message.value) + } - override fun setTyping(friendNumber: ToxFriendNumber, typing: Boolean): Unit = - ToxCoreJni.toxSelfSetTyping(instanceNumber, friendNumber.value, typing) + override val getStatusMessage: ToxStatusMessage + get() = ToxStatusMessage(ToxCoreJni.toxSelfGetStatusMessage(instanceNumber)) - override fun friendSendMessage( - friendNumber: ToxFriendNumber, - messageType: ToxMessageType, - timeDelta: Int, - message: ToxFriendMessage - ): Int = - ToxCoreJni.toxFriendSendMessage( - instanceNumber, friendNumber.value, messageType.ordinal, timeDelta, message.value) - - override fun fileControl( - friendNumber: ToxFriendNumber, - fileNumber: Int, - control: ToxFileControl - ): Unit = - ToxCoreJni.toxFileControl(instanceNumber, friendNumber.value, fileNumber, control.ordinal) + override fun setStatus(status: ToxUserStatus): Unit = ToxCoreJni.toxSelfSetStatus(instanceNumber, status.ordinal) - override fun fileSeek(friendNumber: ToxFriendNumber, fileNumber: Int, position: Long): Unit = - ToxCoreJni.toxFileSeek(instanceNumber, friendNumber.value, fileNumber, position) + override val getStatus: ToxUserStatus + get() = ToxUserStatus.values()[ToxCoreJni.toxSelfGetStatus(instanceNumber)] - override fun fileSend( - friendNumber: ToxFriendNumber, - kind: Int, - fileSize: Long, - fileId: ToxFileId, - filename: ToxFilename - ): Int = - ToxCoreJni.toxFileSend( - instanceNumber, friendNumber.value, kind, fileSize, fileId.value, filename.value) - - override fun fileSendChunk( - friendNumber: ToxFriendNumber, - fileNumber: Int, - position: Long, - data: ByteArray - ): Unit = - ToxCoreJni.toxFileSendChunk(instanceNumber, friendNumber.value, fileNumber, position, data) - - override fun getFileFileId(friendNumber: ToxFriendNumber, fileNumber: Int): ToxFileId = - ToxFileId(ToxCoreJni.toxFileGetFileId(instanceNumber, friendNumber.value, fileNumber)) - - override fun friendSendLossyPacket(friendNumber: ToxFriendNumber, data: ToxLossyPacket): Unit = - ToxCoreJni.toxFriendSendLossyPacket(instanceNumber, friendNumber.value, data.value) - - override fun friendSendLosslessPacket( - friendNumber: ToxFriendNumber, - data: ToxLosslessPacket - ): Unit = ToxCoreJni.toxFriendSendLosslessPacket(instanceNumber, friendNumber.value, data.value) - - private companion object { - - fun checkBootstrapArguments(publicKey: ByteArray): Unit { - if (publicKey.size < ToxCoreConstants.PublicKeySize) { - throw ToxBootstrapException(ToxBootstrapException.Code.BAD_KEY, "Key too short") - } - if (publicKey.size > ToxCoreConstants.PublicKeySize) { - throw ToxBootstrapException(ToxBootstrapException.Code.BAD_KEY, "Key too long") - } + override fun addFriend( + address: ToxFriendAddress, + message: ToxFriendRequestMessage, + ): ToxFriendNumber { + ToxCoreImpl.checkLength("Friend Address", address.value, ToxCoreConstants.ADDRESS_SIZE) + return ToxFriendNumber(ToxCoreJni.toxFriendAdd(instanceNumber, address.value, message.value)) } - fun throwLengthException(name: String, message: String, expectedSize: Int): Unit { - throw IllegalArgumentException("${name} too ${message}, must be ${expectedSize} bytes") + override fun addFriendNorequest(publicKey: ToxPublicKey): ToxFriendNumber { + ToxCoreImpl.checkLength("Public Key", publicKey.value, ToxCoreConstants.PUBLIC_KEY_SIZE) + return ToxFriendNumber(ToxCoreJni.toxFriendAddNorequest(instanceNumber, publicKey.value)) } - fun checkLength(name: String, bytes: ByteArray, expectedSize: Int): Unit { - if (bytes.size < expectedSize) { - throwLengthException(name, "short", expectedSize) - } - if (bytes.size > expectedSize) { - throwLengthException(name, "long", expectedSize) - } + override fun deleteFriend(friendNumber: ToxFriendNumber): Unit = ToxCoreJni.toxFriendDelete(instanceNumber, friendNumber.value) + + override fun friendByPublicKey(publicKey: ToxPublicKey): ToxFriendNumber = + ToxFriendNumber(ToxCoreJni.toxFriendByPublicKey(instanceNumber, publicKey.value)) + + override fun getFriendPublicKey(friendNumber: ToxFriendNumber): ToxPublicKey = + ToxPublicKey(ToxCoreJni.toxFriendGetPublicKey(instanceNumber, friendNumber.value)) + + override fun friendExists(friendNumber: ToxFriendNumber): Boolean = ToxCoreJni.toxFriendExists(instanceNumber, friendNumber.value) + + override val getFriendList: IntArray + get() = ToxCoreJni.toxSelfGetFriendList(instanceNumber) + + override fun setTyping( + friendNumber: ToxFriendNumber, + typing: Boolean, + ): Unit = ToxCoreJni.toxSelfSetTyping(instanceNumber, friendNumber.value, typing) + + override fun friendSendMessage( + friendNumber: ToxFriendNumber, + messageType: ToxMessageType, + timeDelta: Int, + message: ToxFriendMessage, + ): Int = + ToxCoreJni.toxFriendSendMessage( + instanceNumber, + friendNumber.value, + messageType.ordinal, + timeDelta, + message.value, + ) + + override fun fileControl( + friendNumber: ToxFriendNumber, + fileNumber: Int, + control: ToxFileControl, + ): Unit = ToxCoreJni.toxFileControl(instanceNumber, friendNumber.value, fileNumber, control.ordinal) + + override fun fileSeek( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + ): Unit = ToxCoreJni.toxFileSeek(instanceNumber, friendNumber.value, fileNumber, position) + + override fun fileSend( + friendNumber: ToxFriendNumber, + kind: Int, + fileSize: Long, + fileId: ToxFileId, + filename: ToxFilename, + ): Int = + ToxCoreJni.toxFileSend( + instanceNumber, + friendNumber.value, + kind, + fileSize, + fileId.value, + filename.value, + ) + + override fun fileSendChunk( + friendNumber: ToxFriendNumber, + fileNumber: Int, + position: Long, + data: ByteArray, + ): Unit = ToxCoreJni.toxFileSendChunk(instanceNumber, friendNumber.value, fileNumber, position, data) + + override fun getFileFileId( + friendNumber: ToxFriendNumber, + fileNumber: Int, + ): ToxFileId = ToxFileId(ToxCoreJni.toxFileGetFileId(instanceNumber, friendNumber.value, fileNumber)) + + override fun friendSendLossyPacket( + friendNumber: ToxFriendNumber, + data: ToxLossyPacket, + ): Unit = ToxCoreJni.toxFriendSendLossyPacket(instanceNumber, friendNumber.value, data.value) + + override fun friendSendLosslessPacket( + friendNumber: ToxFriendNumber, + data: ToxLosslessPacket, + ): Unit = ToxCoreJni.toxFriendSendLosslessPacket(instanceNumber, friendNumber.value, data.value) + + private companion object { + fun checkBootstrapArguments(publicKey: ByteArray) { + if (publicKey.size < ToxCoreConstants.PUBLIC_KEY_SIZE) { + throw ToxBootstrapException(ToxBootstrapException.Code.BAD_KEY, "Key too short") + } + if (publicKey.size > ToxCoreConstants.PUBLIC_KEY_SIZE) { + throw ToxBootstrapException(ToxBootstrapException.Code.BAD_KEY, "Key too long") + } + } + + fun throwLengthException( + name: String, + message: String, + expectedSize: Int, + ) { + throw IllegalArgumentException("$name too $message, must be $expectedSize bytes") + } + + fun checkLength( + name: String, + bytes: ByteArray, + expectedSize: Int, + ) { + if (bytes.size < expectedSize) { + throwLengthException(name, "short", expectedSize) + } + if (bytes.size > expectedSize) { + throwLengthException(name, "long", expectedSize) + } + } } - } } diff --git a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCryptoImpl.kt b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCryptoImpl.kt index 478a89784..de4f23dcf 100644 --- a/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCryptoImpl.kt +++ b/lib/src/main/java/im/tox/tox4j/impl/jni/ToxCryptoImpl.kt @@ -6,33 +6,40 @@ import im.tox.tox4j.crypto.ToxCryptoConstants private typealias PassKey = ByteArray object ToxCryptoImpl : ToxCrypto { + override fun passKeyEquals( + a: PassKey, + b: PassKey, + ): Boolean = a.contentEquals(b) - override fun passKeyEquals(a: PassKey, b: PassKey): Boolean = a.contentEquals(b) + override fun passKeyToBytes(passKey: PassKey): List = passKey.toList() - override fun passKeyToBytes(passKey: PassKey): List = passKey.toList() + override fun passKeyFromBytes(bytes: List): PassKey? = + if (bytes.size == ToxCryptoConstants.KEY_LENGTH + ToxCryptoConstants.SALT_LENGTH) { + bytes.toByteArray() + } else { + null + } - override fun passKeyFromBytes(bytes: List): PassKey? = - if (bytes.size == ToxCryptoConstants.KeyLength + ToxCryptoConstants.SaltLength) { - bytes.toByteArray() - } else { - null - } + override fun encrypt( + data: ByteArray, + passKey: PassKey, + ): ByteArray = ToxCryptoJni.toxPassKeyEncrypt(data, passKey) - override fun encrypt(data: ByteArray, passKey: PassKey): ByteArray = - ToxCryptoJni.toxPassKeyEncrypt(data, passKey) + override fun getSalt(data: ByteArray): ByteArray = ToxCryptoJni.toxGetSalt(data) - override fun getSalt(data: ByteArray): ByteArray = ToxCryptoJni.toxGetSalt(data) + override fun isDataEncrypted(data: ByteArray): Boolean = ToxCryptoJni.toxIsDataEncrypted(data) - override fun isDataEncrypted(data: ByteArray): Boolean = ToxCryptoJni.toxIsDataEncrypted(data) + override fun passKeyDeriveWithSalt( + passphrase: ByteArray, + salt: ByteArray, + ): PassKey = ToxCryptoJni.toxPassKeyDeriveWithSalt(passphrase, salt) - override fun passKeyDeriveWithSalt(passphrase: ByteArray, salt: ByteArray): PassKey = - ToxCryptoJni.toxPassKeyDeriveWithSalt(passphrase, salt) + override fun passKeyDerive(passphrase: ByteArray): PassKey = ToxCryptoJni.toxPassKeyDerive(passphrase) - override fun passKeyDerive(passphrase: ByteArray): PassKey = - ToxCryptoJni.toxPassKeyDerive(passphrase) + override fun decrypt( + data: ByteArray, + passKey: PassKey, + ): ByteArray = ToxCryptoJni.toxPassKeyDecrypt(data, passKey) - override fun decrypt(data: ByteArray, passKey: PassKey): ByteArray = - ToxCryptoJni.toxPassKeyDecrypt(data, passKey) - - override fun hash(data: ByteArray): ByteArray = ToxCryptoJni.toxHash(data) + override fun hash(data: ByteArray): ByteArray = ToxCryptoJni.toxHash(data) } diff --git a/lib/src/test/java/im/tox/tox4j/core/ToxCoreTest.kt b/lib/src/test/java/im/tox/tox4j/core/ToxCoreTest.kt index 9a44dbf51..2738608af 100644 --- a/lib/src/test/java/im/tox/tox4j/core/ToxCoreTest.kt +++ b/lib/src/test/java/im/tox/tox4j/core/ToxCoreTest.kt @@ -5,90 +5,91 @@ import im.tox.tox4j.core.data.ToxFriendNumber import im.tox.tox4j.core.enums.ToxConnection import im.tox.tox4j.core.options.ToxOptions import im.tox.tox4j.impl.jni.ToxCoreImpl -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.coroutineContext -import kotlin.test.Test import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.coroutineContext +import kotlin.test.Test class ToxCoreTest { - private class Toxes : CoroutineContext.Element { - private val list: MutableList = mutableListOf() + private class Toxes : CoroutineContext.Element { + private val list: MutableList = mutableListOf() - override val key = Toxes + override val key = Toxes - companion object : CoroutineContext.Key { - suspend fun add(makeTox: () -> ToxCore): ToxCore { - val ctx = coroutineContext.get(Toxes) - if (ctx == null) { - throw IllegalStateException("coroutine context has no Toxes object") - } - val tox = makeTox() - ctx.list.add(tox) - return tox - } + companion object : CoroutineContext.Key { + suspend fun add(makeTox: () -> ToxCore): ToxCore { + val ctx = coroutineContext.get(Toxes) + if (ctx == null) { + throw IllegalStateException("coroutine context has no Toxes object") + } + val tox = makeTox() + ctx.list.add(tox) + return tox + } - suspend fun close(): Unit { - val ctx = coroutineContext.get(Toxes) - if (ctx == null) { - throw IllegalStateException("coroutine context has no Toxes object") - } - for (tox in ctx.list) { - tox.close() + suspend fun close() { + val ctx = coroutineContext.get(Toxes) + if (ctx == null) { + throw IllegalStateException("coroutine context has no Toxes object") + } + for (tox in ctx.list) { + tox.close() + } + } } - } } - } - private suspend fun newToxCore(options: ToxOptions): ToxCore = Toxes.add { ToxCoreImpl(options) } + private suspend fun newToxCore(options: ToxOptions): ToxCore = Toxes.add { ToxCoreImpl(options) } - private fun runTox(block: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(Toxes()) { - try { - block() - } finally { - Toxes.close() + private fun runTox(block: suspend CoroutineScope.() -> Unit): Unit = + runBlocking(Toxes()) { + try { + block() + } finally { + Toxes.close() + } } - } - @Test - fun addFriendNorequest_shouldConnectTwoToxes() = runTox { - val tox1 = newToxCore(ToxOptions()) - val tox2 = newToxCore(ToxOptions()) + @Test + fun addFriendNorequest_shouldConnectTwoToxes() = + runTox { + val tox1 = newToxCore(ToxOptions()) + val tox2 = newToxCore(ToxOptions()) - tox2.bootstrap("localhost", tox1.getUdpPort, tox1.getDhtId) + tox2.bootstrap("localhost", tox1.getUdpPort, tox1.getDhtId) - tox1.addFriendNorequest(tox2.getPublicKey) - tox2.addFriendNorequest(tox1.getPublicKey) + tox1.addFriendNorequest(tox2.getPublicKey) + tox2.addFriendNorequest(tox1.getPublicKey) - var connected1 = false - var connected2 = false + var connected1 = false + var connected2 = false - while (!connected1 && !connected2) { - connected1 = - tox1.iterate( - object : ToxCoreEventListener { - override fun friendConnectionStatus( - friendNumber: ToxFriendNumber, - connectionStatus: ToxConnection, - state: Boolean, - ) = connectionStatus != ToxConnection.NONE - }, - connected1, - ) - connected2 = - tox2.iterate( - object : ToxCoreEventListener { - override fun friendConnectionStatus( - friendNumber: ToxFriendNumber, - connectionStatus: ToxConnection, - state: Boolean, - ) = connectionStatus != ToxConnection.NONE - }, - connected2, - ) - delay(tox1.iterationInterval.toLong()) - } - } + while (!connected1 && !connected2) { + connected1 = + tox1.iterate( + object : ToxCoreEventListener { + override fun friendConnectionStatus( + friendNumber: ToxFriendNumber, + connectionStatus: ToxConnection, + state: Boolean, + ) = connectionStatus != ToxConnection.NONE + }, + connected1, + ) + connected2 = + tox2.iterate( + object : ToxCoreEventListener { + override fun friendConnectionStatus( + friendNumber: ToxFriendNumber, + connectionStatus: ToxConnection, + state: Boolean, + ) = connectionStatus != ToxConnection.NONE + }, + connected2, + ) + delay(tox1.iterationInterval.toLong()) + } + } }