mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54c7c905eb | |||
| 07c4cb6a0f | |||
| 921df7bb95 | |||
| 658561392d | |||
| 6bae86d93b | |||
| f579a5270e | |||
| 8b7af71630 | |||
| ca64c76a55 | |||
| 3e6f510c5a | |||
| 75b3f78556 | |||
| 41e61f553c | |||
| 6f5321277e | |||
| b03f3ae814 | |||
| 13e5dd1a8f | |||
| 25eb60c9ff | |||
| b7b34d4ab5 | |||
| d0e5f18329 | |||
| 1aa4c59f1a | |||
| 7fbf37e523 | |||
| 7fee8b0dd5 | |||
| d91bae8c9c | |||
| b7c77651bc | |||
| a787447a2d | |||
| 52a48ec045 | |||
| 0e3d55fc65 | |||
| e76e82634d | |||
| 87c13d5600 | |||
| 8bfff48f94 | |||
| e957f866ce |
@@ -102,7 +102,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Haskell
|
- name: Setup Haskell
|
||||||
uses: haskell/actions/setup@v2
|
uses: haskell-actions/setup@v2
|
||||||
with:
|
with:
|
||||||
ghc-version: ${{ matrix.ghc }}
|
ghc-version: ${{ matrix.ghc }}
|
||||||
cabal-version: "3.10.1.0"
|
cabal-version: "3.10.1.0"
|
||||||
@@ -150,9 +150,13 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
|
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
|
||||||
run: sudo apt install -y desktop-file-utils
|
run: sudo apt install -y desktop-file-utils
|
||||||
|
|
||||||
- name: Install openssl for Mac
|
- name: Install Linux dependencies
|
||||||
|
if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04'
|
||||||
|
run: sudo apt install -y libturbojpeg0-dev
|
||||||
|
|
||||||
|
- name: Install pkg-config for Mac
|
||||||
if: matrix.os == 'macos-latest' || matrix.os == 'macos-13'
|
if: matrix.os == 'macos-latest' || matrix.os == 'macos-13'
|
||||||
run: brew install openssl@3.0
|
run: brew install openssl@3.0 pkg-config jpeg-turbo
|
||||||
|
|
||||||
- name: Unix prepare cabal.project.local for Ubuntu
|
- name: Unix prepare cabal.project.local for Ubuntu
|
||||||
if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04'
|
if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04'
|
||||||
@@ -230,7 +234,7 @@ jobs:
|
|||||||
APPLE_SIMPLEX_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_APPLE_ID }}
|
APPLE_SIMPLEX_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_APPLE_ID }}
|
||||||
APPLE_SIMPLEX_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_PASSWORD }}
|
APPLE_SIMPLEX_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
scripts/build-desktop-mac.sh
|
scripts/ci/build-desktop-mac.sh
|
||||||
path=$(echo $PWD/apps/multiplatform/release/main/dmg/SimpleX-*.dmg)
|
path=$(echo $PWD/apps/multiplatform/release/main/dmg/SimpleX-*.dmg)
|
||||||
echo "package_path=$path" >> $GITHUB_OUTPUT
|
echo "package_path=$path" >> $GITHUB_OUTPUT
|
||||||
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
|
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
|
||||||
@@ -310,9 +314,7 @@ jobs:
|
|||||||
# Unix /
|
# Unix /
|
||||||
|
|
||||||
# / Windows
|
# / Windows
|
||||||
|
# rm -rf dist-newstyle/src/direct-sq* is here because of the bug in cabal's dependency which prevents second build from finishing
|
||||||
# * In powershell multiline commands do not fail if individual commands fail - https://github.community/t/multiline-commands-on-windows-do-not-fail-if-individual-commands-fail/16753
|
|
||||||
# * And GitHub Actions does not support parameterizing shell in a matrix job - https://github.community/t/using-matrix-to-specify-shell-is-it-possible/17065
|
|
||||||
|
|
||||||
- name: 'Setup MSYS2'
|
- name: 'Setup MSYS2'
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
@@ -324,6 +326,7 @@ jobs:
|
|||||||
git
|
git
|
||||||
perl
|
perl
|
||||||
make
|
make
|
||||||
|
mingw-w64-x86_64-libjpeg-turbo
|
||||||
pacboy: >-
|
pacboy: >-
|
||||||
toolchain:p
|
toolchain:p
|
||||||
cmake:p
|
cmake:p
|
||||||
|
|||||||
@@ -25,6 +25,18 @@ public func writeCryptoFile(path: String, data: Data) throws -> CryptoFileArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func writeCryptoImage(maxSize: Int, path: String, data: Data, encrypted: Bool) throws -> CryptoFileArgs {
|
||||||
|
let ptr: UnsafeMutableRawPointer = malloc(data.count)
|
||||||
|
memcpy(ptr, (data as NSData).bytes, data.count)
|
||||||
|
var cPath = path.cString(using: .utf8)!
|
||||||
|
let cjson = chat_write_image(getChatCtrl(), maxSize, &cPath, ptr, Int32(data.count), encrypted)!
|
||||||
|
let d = fromCString(cjson).data(using: .utf8)!
|
||||||
|
switch try jsonDecoder.decode(WriteFileResult.self, from: d) {
|
||||||
|
case let .result(cfArgs): return cfArgs
|
||||||
|
case let .error(err): throw RuntimeError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func readCryptoFile(path: String, cryptoArgs: CryptoFileArgs) throws -> Data {
|
public func readCryptoFile(path: String, cryptoArgs: CryptoFileArgs) throws -> Data {
|
||||||
var cPath = path.cString(using: .utf8)!
|
var cPath = path.cString(using: .utf8)!
|
||||||
var cKey = cryptoArgs.fileKey.cString(using: .utf8)!
|
var cKey = cryptoArgs.fileKey.cString(using: .utf8)!
|
||||||
|
|||||||
@@ -223,6 +223,17 @@ public func saveFile(_ data: Data, _ fileName: String, encrypted: Bool) -> Crypt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func saveImage(_ data: Data, _ fileName: String, maxSize: Long, encrypted: Bool) -> CryptoFile? {
|
||||||
|
let filePath = getAppFilePath(fileName)
|
||||||
|
do {
|
||||||
|
let cfArgs = try writeCryptoImage(maxSize: maxSize, path: filePath.path, data: data, encrypted: encrypted)
|
||||||
|
return CryptoFile(filePath: fileName, cryptoArgs: cfArgs)
|
||||||
|
} catch {
|
||||||
|
logger.error("FileUtils.saveImage error: \(error.localizedDescription)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func removeFile(_ url: URL) {
|
public func removeFile(_ url: URL) {
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(atPath: url.path)
|
try FileManager.default.removeItem(atPath: url.path)
|
||||||
|
|||||||
@@ -101,19 +101,27 @@ public func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func resizeImageToStrSizeSync(_ image: UIImage, maxDataSize: Int64) -> String? {
|
public func resizeImageToStrSizeSync(_ image: UIImage, maxDataSize: Int64) -> String? {
|
||||||
var img = image
|
// XXX: only needed when the original encoding isn't available
|
||||||
let hasAlpha = imageHasAlpha(image)
|
let tmpFile = generateNewFileName(getTempFilesDirectory().path + "/" + "resize", "png", fullPath: true)
|
||||||
var str = compressImageStr(img, hasAlpha: hasAlpha)
|
// encode as png and let the backend deal with alpha and formats
|
||||||
var dataSize = str?.count ?? 0
|
guard let d = image.pngData() else { return nil }
|
||||||
while dataSize != 0 && dataSize > maxDataSize {
|
if let _ = saveFile(d, tmpFile, encrypted: false) {
|
||||||
let ratio = sqrt(Double(dataSize) / Double(maxDataSize))
|
defer { removeFile(tmpFile) }
|
||||||
let clippedRatio = min(ratio, 2.0)
|
let ptr = chat_resize_image_to_str_size(tmpFile, maxDataSize)
|
||||||
img = reduceSize(img, ratio: clippedRatio, hasAlpha: hasAlpha)
|
if let ptr = ptr {
|
||||||
str = compressImageStr(img, hasAlpha: hasAlpha)
|
let str = fromCString(ptr)
|
||||||
dataSize = str?.count ?? 0
|
let dataSize = str.count
|
||||||
|
if dataSize <= 0 { return nil }
|
||||||
|
logger.debug("resizeImageToStrSize final \(dataSize)")
|
||||||
|
return str
|
||||||
|
} else {
|
||||||
|
logger.error("resizeImageToStrSize failed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("saveFile failed")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
logger.debug("resizeImageToStrSize final \(dataSize)")
|
|
||||||
return str
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) async -> String? {
|
public func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) async -> String? {
|
||||||
@@ -311,7 +319,7 @@ private func getTimestamp() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func dropImagePrefix(_ s: String) -> String {
|
public func dropImagePrefix(_ s: String) -> String {
|
||||||
dropPrefix(dropPrefix(s, "data:image/png;base64,"), "data:image/jpg;base64,")
|
dropPrefix(dropPrefix(dropPrefix(s, "data:image/png;base64,"), "data:image/jpg;base64,"), "data:image/jpeg;base64,")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dropPrefix(_ s: String, _ prefix: String) -> String {
|
private func dropPrefix(_ s: String, _ prefix: String) -> String {
|
||||||
|
|||||||
@@ -29,10 +29,14 @@ extern char *chat_valid_name(char *name);
|
|||||||
extern int chat_json_length(char *str);
|
extern int chat_json_length(char *str);
|
||||||
extern char *chat_encrypt_media(chat_ctrl ctl, char *key, char *frame, int len);
|
extern char *chat_encrypt_media(chat_ctrl ctl, char *key, char *frame, int len);
|
||||||
extern char *chat_decrypt_media(char *key, char *frame, int len);
|
extern char *chat_decrypt_media(char *key, char *frame, int len);
|
||||||
|
extern char *chat_resize_image_to_str_size(const char *path, long maxSize);
|
||||||
|
|
||||||
// chat_write_file returns null-terminated string with JSON of WriteFileResult
|
// chat_write_file returns null-terminated string with JSON of WriteFileResult
|
||||||
extern char *chat_write_file(chat_ctrl ctl, char *path, char *data, int len);
|
extern char *chat_write_file(chat_ctrl ctl, char *path, char *data, int len);
|
||||||
|
|
||||||
|
// chat_write_image returns null-terminated string with JSON of WriteFileResult
|
||||||
|
extern char *chat_write_image(chat_ctrl ctl, long maxSize, char *path, char *data, int len, bool encrypted);
|
||||||
|
|
||||||
// chat_read_file returns a buffer with:
|
// chat_read_file returns a buffer with:
|
||||||
// result status (1 byte), then if
|
// result status (1 byte), then if
|
||||||
// status == 0 (success): buffer length (uint32, 4 bytes), buffer of specified length.
|
// status == 0 (success): buffer length (uint32, 4 bytes), buffer of specified length.
|
||||||
|
|||||||
+32
-29
@@ -14,8 +14,12 @@ import boofcv.android.ConvertBitmap
|
|||||||
import boofcv.struct.image.GrayU8
|
import boofcv.struct.image.GrayU8
|
||||||
import chat.simplex.common.R
|
import chat.simplex.common.R
|
||||||
import chat.simplex.common.views.helpers.errorBitmap
|
import chat.simplex.common.views.helpers.errorBitmap
|
||||||
|
import chat.simplex.common.views.helpers.generateNewFileName
|
||||||
import chat.simplex.common.views.helpers.getFileName
|
import chat.simplex.common.views.helpers.getFileName
|
||||||
|
import chat.simplex.common.views.helpers.removeFile
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -25,26 +29,25 @@ actual fun base64ToBitmap(base64ImageString: String): ImageBitmap {
|
|||||||
val imageString = base64ImageString
|
val imageString = base64ImageString
|
||||||
.removePrefix("data:image/png;base64,")
|
.removePrefix("data:image/png;base64,")
|
||||||
.removePrefix("data:image/jpg;base64,")
|
.removePrefix("data:image/jpg;base64,")
|
||||||
|
.removePrefix("data:image/jpeg;base64,")
|
||||||
return try {
|
return try {
|
||||||
val imageBytes = Base64.decode(imageString, Base64.NO_WRAP)
|
val imageBytes = Base64.decode(imageString, Base64.NO_WRAP)
|
||||||
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size).asImageBitmap()
|
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size).asImageBitmap()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "base64ToBitmap error: $e")
|
Log.e(TAG, "base64ToBitmap error: $e for input '$base64ImageString' -> '$imageString'")
|
||||||
errorBitmap.asImageBitmap()
|
errorBitmap.asImageBitmap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String {
|
actual fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String {
|
||||||
var img = image
|
val tmpFileName = generateNewFileName("IMG", "png", tmpDir)
|
||||||
var str = compressImageStr(img)
|
val tmpFile = File(tmpDir, tmpFileName)
|
||||||
while (str.length > maxDataSize) {
|
val output = FileOutputStream(tmpFile)
|
||||||
val ratio = sqrt(str.length.toDouble() / maxDataSize.toDouble())
|
compressImageData(image, true).writeTo(output)
|
||||||
val clippedRatio = min(ratio, 2.0)
|
output.flush()
|
||||||
val width = (img.width.toDouble() / clippedRatio).toInt()
|
output.close()
|
||||||
val height = img.height * width / img.width
|
var str = chatResizeImageToStrSize(tmpFile.absolutePath, maxDataSize)
|
||||||
img = Bitmap.createScaledBitmap(img.asAndroidBitmap(), width, height, true).asImageBitmap()
|
removeFile(tmpFileName)
|
||||||
str = compressImageStr(img)
|
|
||||||
}
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,11 +74,11 @@ fun Bitmap.clipToCircle(): Bitmap {
|
|||||||
return circle
|
return circle
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun compressImageStr(bitmap: ImageBitmap): String {
|
// actual fun compressImageStr(bitmap: ImageBitmap): String {
|
||||||
val usePng = bitmap.hasAlpha()
|
// val usePng = bitmap.hasAlpha()
|
||||||
val ext = if (usePng) "png" else "jpg"
|
// val ext = if (usePng) "png" else "jpg"
|
||||||
return "data:image/$ext;base64," + Base64.encodeToString(compressImageData(bitmap, usePng).toByteArray(), Base64.NO_WRAP)
|
// return "data:image/$ext;base64," + Base64.encodeToString(compressImageData(bitmap, usePng).toByteArray(), Base64.NO_WRAP)
|
||||||
}
|
// }
|
||||||
|
|
||||||
actual fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream {
|
actual fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream {
|
||||||
val stream = ByteArrayOutputStream()
|
val stream = ByteArrayOutputStream()
|
||||||
@@ -83,19 +86,19 @@ actual fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOut
|
|||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream {
|
// actual fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream {
|
||||||
var img = image
|
// var img = image
|
||||||
var stream = compressImageData(img, usePng)
|
// var stream = compressImageData(img, usePng)
|
||||||
while (stream.size() > maxDataSize) {
|
// while (stream.size() > maxDataSize) {
|
||||||
val ratio = sqrt(stream.size().toDouble() / maxDataSize.toDouble())
|
// val ratio = sqrt(stream.size().toDouble() / maxDataSize.toDouble())
|
||||||
val clippedRatio = min(ratio, 2.0)
|
// val clippedRatio = min(ratio, 2.0)
|
||||||
val width = (img.width.toDouble() / clippedRatio).toInt()
|
// val width = (img.width.toDouble() / clippedRatio).toInt()
|
||||||
val height = img.height * width / img.width
|
// val height = img.height * width / img.width
|
||||||
img = Bitmap.createScaledBitmap(img.asAndroidBitmap(), width, height, true).asImageBitmap()
|
// img = Bitmap.createScaledBitmap(img.asAndroidBitmap(), width, height, true).asImageBitmap()
|
||||||
stream = compressImageData(img, usePng)
|
// stream = compressImageData(img, usePng)
|
||||||
}
|
// }
|
||||||
return stream
|
// return stream
|
||||||
}
|
// }
|
||||||
|
|
||||||
actual fun GrayU8.toImageBitmap(): ImageBitmap = ConvertBitmap.grayToBitmap(this, Bitmap.Config.RGB_565).asImageBitmap()
|
actual fun GrayU8.toImageBitmap(): ImageBitmap = ConvertBitmap.grayToBitmap(this, Bitmap.Config.RGB_565).asImageBitmap()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
//#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
//#include <android/log.h>
|
//#include <android/log.h>
|
||||||
|
|
||||||
// from the RTS
|
// from the RTS
|
||||||
@@ -68,9 +69,31 @@ extern char *chat_password_hash(const char *pwd, const char *salt);
|
|||||||
extern char *chat_valid_name(const char *name);
|
extern char *chat_valid_name(const char *name);
|
||||||
extern int chat_json_length(const char *str);
|
extern int chat_json_length(const char *str);
|
||||||
extern char *chat_write_file(chat_ctrl ctrl, const char *path, char *ptr, int length);
|
extern char *chat_write_file(chat_ctrl ctrl, const char *path, char *ptr, int length);
|
||||||
|
extern char *chat_write_image(chat_ctrl ctrl, long max_size, const char *path, char *ptr, int length, bool encrypt);
|
||||||
extern char *chat_read_file(const char *path, const char *key, const char *nonce);
|
extern char *chat_read_file(const char *path, const char *key, const char *nonce);
|
||||||
extern char *chat_encrypt_file(chat_ctrl ctrl, const char *from_path, const char *to_path);
|
extern char *chat_encrypt_file(chat_ctrl ctrl, const char *from_path, const char *to_path);
|
||||||
extern char *chat_decrypt_file(const char *from_path, const char *key, const char *nonce, const char *to_path);
|
extern char *chat_decrypt_file(const char *from_path, const char *key, const char *nonce, const char *to_path);
|
||||||
|
extern char *chat_resize_image_to_str_size(const char *from_path, long max_size);
|
||||||
|
|
||||||
|
char * encode_to_utf8_chars(JNIEnv *env, jstring string) {
|
||||||
|
if (!string) return "";
|
||||||
|
|
||||||
|
const jclass cls_string = (*env)->FindClass(env, "java/lang/String");
|
||||||
|
const jmethodID mid_getBytes = (*env)->GetMethodID(env, cls_string, "getBytes", "(Ljava/lang/String;)[B");
|
||||||
|
const jbyteArray jbyte_array = (jbyteArray) (*env)->CallObjectMethod(env, string, mid_getBytes, (*env)->NewStringUTF(env, "UTF-8"));
|
||||||
|
jint length = (jint) (*env)->GetArrayLength(env, jbyte_array);
|
||||||
|
jbyte *jbytes = malloc(length + 1);
|
||||||
|
(*env)->GetByteArrayRegion(env, jbyte_array, 0, length, jbytes);
|
||||||
|
// char * should be null terminated but jbyte * isn't. Terminate it with \0. Otherwise, Haskell will not see the end of string
|
||||||
|
jbytes[length] = '\0';
|
||||||
|
|
||||||
|
//for (int i = 0; i < length; ++i)
|
||||||
|
// fprintf(stderr, "%d: %02x\n", i, jbytes[i]);
|
||||||
|
|
||||||
|
(*env)->DeleteLocalRef(env, jbyte_array);
|
||||||
|
(*env)->DeleteLocalRef(env, cls_string);
|
||||||
|
return (char *) jbytes;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_chat_simplex_common_platform_CoreKt_chatMigrateInit(JNIEnv *env, __unused jclass clazz, jstring dbPath, jstring dbKey, jstring confirm) {
|
Java_chat_simplex_common_platform_CoreKt_chatMigrateInit(JNIEnv *env, __unused jclass clazz, jstring dbPath, jstring dbKey, jstring confirm) {
|
||||||
@@ -182,6 +205,16 @@ Java_chat_simplex_common_platform_CoreKt_chatWriteFile(JNIEnv *env, jclass clazz
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_chat_simplex_common_platform_CoreKt_chatWriteImage(JNIEnv *env, jclass clazz, jlong controller, jlong maxSize, jstring path, jobject buffer, jboolean encrypt) {
|
||||||
|
const char *_path = (*env)->GetStringUTFChars(env, path, JNI_FALSE);
|
||||||
|
jbyte *buff = (jbyte *) (*env)->GetDirectBufferAddress(env, buffer);
|
||||||
|
jlong capacity = (*env)->GetDirectBufferCapacity(env, buffer);
|
||||||
|
jstring res = (*env)->NewStringUTF(env, chat_write_image((void*)controller, maxSize, _path, buff, capacity, encrypt));
|
||||||
|
(*env)->ReleaseStringUTFChars(env, path, _path);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_chat_simplex_common_platform_CoreKt_chatReadFile(JNIEnv *env, jclass clazz, jstring path, jstring key, jstring nonce) {
|
Java_chat_simplex_common_platform_CoreKt_chatReadFile(JNIEnv *env, jclass clazz, jstring path, jstring key, jstring nonce) {
|
||||||
const char *_path = (*env)->GetStringUTFChars(env, path, JNI_FALSE);
|
const char *_path = (*env)->GetStringUTFChars(env, path, JNI_FALSE);
|
||||||
@@ -244,3 +277,11 @@ Java_chat_simplex_common_platform_CoreKt_chatDecryptFile(JNIEnv *env, jclass cla
|
|||||||
(*env)->ReleaseStringUTFChars(env, to_path, _to_path);
|
(*env)->ReleaseStringUTFChars(env, to_path, _to_path);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_chat_simplex_common_platform_CoreKt_chatResizeImageToStrSize(JNIEnv *env, jclass clazz, jstring from_path, jlong max_size) {
|
||||||
|
const char *_from_path = (*env)->GetStringUTFChars(env, from_path, JNI_FALSE);
|
||||||
|
jstring res = (*env)->NewStringUTF(env, chat_resize_image_to_str_size(_from_path, max_size));
|
||||||
|
(*env)->ReleaseStringUTFChars(env, from_path, _from_path);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ if(NOT APPLE)
|
|||||||
else()
|
else()
|
||||||
# Without direct linking it can't find hs_init in linking step
|
# Without direct linking it can't find hs_init in linking step
|
||||||
add_library( rts SHARED IMPORTED )
|
add_library( rts SHARED IMPORTED )
|
||||||
FILE(GLOB RTSLIB ${CMAKE_SOURCE_DIR}/libs/${OS_LIB_PATH}-${OS_LIB_ARCH}/deps/libHSrts*_thr-*.${OS_LIB_EXT})
|
FILE(GLOB RTSLIB ${CMAKE_SOURCE_DIR}/libs/${OS_LIB_PATH}-${OS_LIB_ARCH}/libHSrts*_thr-*.${OS_LIB_EXT})
|
||||||
set_target_properties( rts PROPERTIES IMPORTED_LOCATION ${RTSLIB})
|
set_target_properties( rts PROPERTIES IMPORTED_LOCATION ${RTSLIB})
|
||||||
|
|
||||||
target_link_libraries(app-lib rts simplex)
|
target_link_libraries(app-lib rts simplex)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -41,9 +42,11 @@ extern char *chat_password_hash(const char *pwd, const char *salt);
|
|||||||
extern char *chat_valid_name(const char *name);
|
extern char *chat_valid_name(const char *name);
|
||||||
extern int chat_json_length(const char *str);
|
extern int chat_json_length(const char *str);
|
||||||
extern char *chat_write_file(chat_ctrl ctrl, const char *path, char *ptr, int length);
|
extern char *chat_write_file(chat_ctrl ctrl, const char *path, char *ptr, int length);
|
||||||
|
extern char *chat_write_image(chat_ctrl ctrl, long max_size, const char *path, char *ptr, int length, bool encrypt);
|
||||||
extern char *chat_read_file(const char *path, const char *key, const char *nonce);
|
extern char *chat_read_file(const char *path, const char *key, const char *nonce);
|
||||||
extern char *chat_encrypt_file(chat_ctrl ctrl, const char *from_path, const char *to_path);
|
extern char *chat_encrypt_file(chat_ctrl ctrl, const char *from_path, const char *to_path);
|
||||||
extern char *chat_decrypt_file(const char *from_path, const char *key, const char *nonce, const char *to_path);
|
extern char *chat_decrypt_file(const char *from_path, const char *key, const char *nonce, const char *to_path);
|
||||||
|
extern char *chat_resize_image_to_str_size(const char *from_path, long max_size);
|
||||||
|
|
||||||
// As a reference: https://stackoverflow.com/a/60002045
|
// As a reference: https://stackoverflow.com/a/60002045
|
||||||
jstring decode_to_utf8_string(JNIEnv *env, char *string) {
|
jstring decode_to_utf8_string(JNIEnv *env, char *string) {
|
||||||
@@ -192,6 +195,16 @@ Java_chat_simplex_common_platform_CoreKt_chatWriteFile(JNIEnv *env, jclass clazz
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_chat_simplex_common_platform_CoreKt_chatWriteImage(JNIEnv *env, jclass clazz, jlong controller, jlong maxSize, jstring path, jobject buffer, jboolean encrypt) {
|
||||||
|
const char *_path = encode_to_utf8_chars(env, path);
|
||||||
|
jbyte *buff = (jbyte *) (*env)->GetDirectBufferAddress(env, buffer);
|
||||||
|
jlong capacity = (*env)->GetDirectBufferCapacity(env, buffer);
|
||||||
|
jstring res = decode_to_utf8_string(env, chat_write_image((void*)controller, maxSize, _path, buff, capacity, encrypt));
|
||||||
|
(*env)->ReleaseStringUTFChars(env, path, _path);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_chat_simplex_common_platform_CoreKt_chatReadFile(JNIEnv *env, jclass clazz, jstring path, jstring key, jstring nonce) {
|
Java_chat_simplex_common_platform_CoreKt_chatReadFile(JNIEnv *env, jclass clazz, jstring path, jstring key, jstring nonce) {
|
||||||
const char *_path = encode_to_utf8_chars(env, path);
|
const char *_path = encode_to_utf8_chars(env, path);
|
||||||
@@ -254,3 +267,11 @@ Java_chat_simplex_common_platform_CoreKt_chatDecryptFile(JNIEnv *env, jclass cla
|
|||||||
(*env)->ReleaseStringUTFChars(env, to_path, _to_path);
|
(*env)->ReleaseStringUTFChars(env, to_path, _to_path);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_chat_simplex_common_platform_CoreKt_chatResizeImageToStrSize(JNIEnv *env, jclass clazz, jstring from_path, jlong max_size) {
|
||||||
|
const char *_from_path = encode_to_utf8_chars(env, from_path);
|
||||||
|
jstring res = decode_to_utf8_string(env, chat_resize_image_to_str_size(_from_path, max_size));
|
||||||
|
(*env)->ReleaseStringUTFChars(env, from_path, _from_path);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|||||||
+14
@@ -1,5 +1,6 @@
|
|||||||
package chat.simplex.common.model
|
package chat.simplex.common.model
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import chat.simplex.common.platform.*
|
import chat.simplex.common.platform.*
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@@ -32,6 +33,19 @@ fun writeCryptoFile(path: String, data: ByteArray): CryptoFileArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun writeCryptoImage(maxSize: Long, image: ImageBitmap, path: String, encrypt: Boolean): CryptoFileArgs {
|
||||||
|
val ctrl = ChatController.ctrl ?: throw Exception("Controller is not initialized")
|
||||||
|
val data = compressImageData(image, image.hasAlpha).toByteArray()
|
||||||
|
val buffer = ByteBuffer.allocateDirect(data.size)
|
||||||
|
buffer.put(data)
|
||||||
|
buffer.rewind()
|
||||||
|
val str = chatWriteImage(ctrl, maxSize, path, buffer, encrypt)
|
||||||
|
return when (val d = json.decodeFromString(WriteFileResult.serializer(), str)) {
|
||||||
|
is WriteFileResult.Result -> d.cryptoArgs
|
||||||
|
is WriteFileResult.Error -> throw Exception(d.writeError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun readCryptoFile(path: String, cryptoArgs: CryptoFileArgs): ByteArray {
|
fun readCryptoFile(path: String, cryptoArgs: CryptoFileArgs): ByteArray {
|
||||||
val res: Array<Any> = chatReadFile(path, cryptoArgs.fileKey, cryptoArgs.fileNonce)
|
val res: Array<Any> = chatReadFile(path, cryptoArgs.fileKey, cryptoArgs.fileNonce)
|
||||||
val status = (res[0] as Integer).toInt()
|
val status = (res[0] as Integer).toInt()
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ external fun chatPasswordHash(pwd: String, salt: String): String
|
|||||||
external fun chatValidName(name: String): String
|
external fun chatValidName(name: String): String
|
||||||
external fun chatJsonLength(str: String): Int
|
external fun chatJsonLength(str: String): Int
|
||||||
external fun chatWriteFile(ctrl: ChatCtrl, path: String, buffer: ByteBuffer): String
|
external fun chatWriteFile(ctrl: ChatCtrl, path: String, buffer: ByteBuffer): String
|
||||||
|
external fun chatWriteImage(ctrl: ChatCtrl, maxSize: Long, path: String, buffer: ByteBuffer, encrypt: Boolean): String
|
||||||
external fun chatReadFile(path: String, key: String, nonce: String): Array<Any>
|
external fun chatReadFile(path: String, key: String, nonce: String): Array<Any>
|
||||||
external fun chatEncryptFile(ctrl: ChatCtrl, fromPath: String, toPath: String): String
|
external fun chatEncryptFile(ctrl: ChatCtrl, fromPath: String, toPath: String): String
|
||||||
external fun chatDecryptFile(fromPath: String, key: String, nonce: String, toPath: String): String
|
external fun chatDecryptFile(fromPath: String, key: String, nonce: String, toPath: String): String
|
||||||
|
external fun chatResizeImageToStrSize(fromPath: String, maxSize: Long): String
|
||||||
|
|
||||||
val chatModel: ChatModel
|
val chatModel: ChatModel
|
||||||
get() = chatController.chatModel
|
get() = chatController.chatModel
|
||||||
|
|||||||
+3
-2
@@ -7,10 +7,11 @@ import java.io.InputStream
|
|||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
expect fun base64ToBitmap(base64ImageString: String): ImageBitmap
|
expect fun base64ToBitmap(base64ImageString: String): ImageBitmap
|
||||||
|
// XXX: Not a part of platform services anymore?
|
||||||
expect fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String
|
expect fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String
|
||||||
expect fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream
|
// expect fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream
|
||||||
expect fun cropToSquare(image: ImageBitmap): ImageBitmap
|
expect fun cropToSquare(image: ImageBitmap): ImageBitmap
|
||||||
expect fun compressImageStr(bitmap: ImageBitmap): String
|
// expect fun compressImageStr(bitmap: ImageBitmap): String
|
||||||
expect fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream
|
expect fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream
|
||||||
|
|
||||||
expect fun GrayU8.toImageBitmap(): ImageBitmap
|
expect fun GrayU8.toImageBitmap(): ImageBitmap
|
||||||
|
|||||||
+16
-26
@@ -169,24 +169,19 @@ fun saveImage(image: ImageBitmap): CryptoFile? {
|
|||||||
return try {
|
return try {
|
||||||
val encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get()
|
val encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get()
|
||||||
val ext = if (image.hasAlpha()) "png" else "jpg"
|
val ext = if (image.hasAlpha()) "png" else "jpg"
|
||||||
val dataResized = resizeImageToDataSize(image, ext == "png", maxDataSize = MAX_IMAGE_SIZE)
|
|
||||||
val destFileName = generateNewFileName("IMG", ext, File(getAppFilePath("")))
|
val destFileName = generateNewFileName("IMG", ext, File(getAppFilePath("")))
|
||||||
val destFile = File(getAppFilePath(destFileName))
|
val destFile = File(getAppFilePath(destFileName))
|
||||||
if (encrypted) {
|
try {
|
||||||
try {
|
val args = writeCryptoImage(MAX_IMAGE_SIZE, image, destFile.absolutePath, encrypted)
|
||||||
val args = writeCryptoFile(destFile.absolutePath, dataResized.toByteArray())
|
if (encrypted) {
|
||||||
CryptoFile(destFileName, args)
|
CryptoFile(destFileName, args)
|
||||||
} catch (e: Exception) {
|
} else {
|
||||||
Log.e(TAG, "Unable to write crypto file: " + e.stackTraceToString())
|
CryptoFile.plain(destFileName)
|
||||||
AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.error), text = e.stackTraceToString())
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e: Exception) {
|
||||||
val output = FileOutputStream(destFile)
|
Log.e(TAG, "Unable to write crypto file: " + e.stackTraceToString())
|
||||||
dataResized.writeTo(output)
|
AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.error), text = e.stackTraceToString())
|
||||||
output.flush()
|
null
|
||||||
output.close()
|
|
||||||
CryptoFile.plain(destFileName)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Util.kt saveImage error: ${e.stackTraceToString()}")
|
Log.e(TAG, "Util.kt saveImage error: ${e.stackTraceToString()}")
|
||||||
@@ -198,14 +193,10 @@ fun desktopSaveImageInTmp(uri: URI): CryptoFile? {
|
|||||||
val image = getBitmapFromUri(uri) ?: return null
|
val image = getBitmapFromUri(uri) ?: return null
|
||||||
return try {
|
return try {
|
||||||
val ext = if (image.hasAlpha()) "png" else "jpg"
|
val ext = if (image.hasAlpha()) "png" else "jpg"
|
||||||
val dataResized = resizeImageToDataSize(image, ext == "png", maxDataSize = MAX_IMAGE_SIZE)
|
|
||||||
val destFileName = generateNewFileName("IMG", ext, tmpDir)
|
val destFileName = generateNewFileName("IMG", ext, tmpDir)
|
||||||
val destFile = File(tmpDir, destFileName)
|
val destFile = File(tmpDir, destFileName)
|
||||||
val output = FileOutputStream(destFile)
|
val args = writeCryptoImage(MAX_IMAGE_SIZE, image, destFile.absolutePath, false)
|
||||||
dataResized.writeTo(output)
|
CryptoFile(destFileName, args)
|
||||||
output.flush()
|
|
||||||
output.close()
|
|
||||||
CryptoFile.plain(destFile.absolutePath)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Util.kt desktopSaveImageInTmp error: ${e.stackTraceToString()}")
|
Log.e(TAG, "Util.kt desktopSaveImageInTmp error: ${e.stackTraceToString()}")
|
||||||
null
|
null
|
||||||
@@ -301,11 +292,7 @@ fun saveWallpaperFile(uri: URI): String? {
|
|||||||
fun saveWallpaperFile(image: ImageBitmap): String {
|
fun saveWallpaperFile(image: ImageBitmap): String {
|
||||||
val destFileName = generateNewFileName("wallpaper", "jpg", File(getWallpaperFilePath("")))
|
val destFileName = generateNewFileName("wallpaper", "jpg", File(getWallpaperFilePath("")))
|
||||||
val destFile = File(getWallpaperFilePath(destFileName))
|
val destFile = File(getWallpaperFilePath(destFileName))
|
||||||
val dataResized = resizeImageToDataSize(image, false, maxDataSize = 5_000_000)
|
writeCryptoImage(5_000_000, image, destFile.absolutePath, false)
|
||||||
val output = FileOutputStream(destFile)
|
|
||||||
dataResized.use {
|
|
||||||
it.writeTo(output)
|
|
||||||
}
|
|
||||||
return destFile.name
|
return destFile.name
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +352,10 @@ fun formatBytes(bytes: Long): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun removeFile(fileName: String): Boolean {
|
fun removeFile(fileName: String): Boolean {
|
||||||
val file = File(getAppFilePath(fileName))
|
return removeFile(File(getAppFilePath(fileName)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFile(file: File): Boolean {
|
||||||
val fileDeleted = file.delete()
|
val fileDeleted = file.delete()
|
||||||
if (!fileDeleted) {
|
if (!fileDeleted) {
|
||||||
Log.e(TAG, "Util.kt removeFile error")
|
Log.e(TAG, "Util.kt removeFile error")
|
||||||
|
|||||||
+38
-36
@@ -5,6 +5,8 @@ import androidx.compose.ui.unit.IntOffset
|
|||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import boofcv.io.image.ConvertBufferedImage
|
import boofcv.io.image.ConvertBufferedImage
|
||||||
import boofcv.struct.image.GrayU8
|
import boofcv.struct.image.GrayU8
|
||||||
|
import chat.simplex.common.views.helpers.generateNewFileName
|
||||||
|
import chat.simplex.common.views.helpers.removeFile
|
||||||
import chat.simplex.res.MR
|
import chat.simplex.res.MR
|
||||||
import org.jetbrains.skia.Image
|
import org.jetbrains.skia.Image
|
||||||
import java.awt.RenderingHints
|
import java.awt.RenderingHints
|
||||||
@@ -25,40 +27,40 @@ actual fun base64ToBitmap(base64ImageString: String): ImageBitmap {
|
|||||||
val imageString = base64ImageString
|
val imageString = base64ImageString
|
||||||
.removePrefix("data:image/png;base64,")
|
.removePrefix("data:image/png;base64,")
|
||||||
.removePrefix("data:image/jpg;base64,")
|
.removePrefix("data:image/jpg;base64,")
|
||||||
|
.removePrefix("data:image/jpeg;base64,")
|
||||||
return try {
|
return try {
|
||||||
ImageIO.read(ByteArrayInputStream(Base64.getMimeDecoder().decode(imageString))).toComposeImageBitmap()
|
ImageIO.read(ByteArrayInputStream(Base64.getMimeDecoder().decode(imageString))).toComposeImageBitmap()
|
||||||
} catch (e: IOException) {
|
} catch (e: Exception) { // ByteArrayInputStream returns null
|
||||||
Log.e(TAG, "base64ToBitmap error: $e")
|
Log.e(TAG, "base64ToBitmap error: $e for input '$base64ImageString' -> '$imageString'")
|
||||||
errorBitmap()
|
errorBitmap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String {
|
actual fun resizeImageToStrSize(image: ImageBitmap, maxDataSize: Long): String {
|
||||||
var img = image
|
val tmpFileName = generateNewFileName("IMG", "png", tmpDir)
|
||||||
var str = compressImageStr(img)
|
val tmpFile = File(tmpDir, tmpFileName)
|
||||||
while (str.length > maxDataSize) {
|
val output = FileOutputStream(tmpFile)
|
||||||
val ratio = sqrt(str.length.toDouble() / maxDataSize.toDouble())
|
compressImageData(image, true).writeTo(output)
|
||||||
val clippedRatio = kotlin.math.min(ratio, 2.0)
|
output.flush()
|
||||||
val width = (img.width.toDouble() / clippedRatio).toInt()
|
output.close()
|
||||||
val height = img.height * width / img.width
|
var str = chatResizeImageToStrSize(tmpFile.absolutePath, maxDataSize)
|
||||||
img = img.scale(width, height)
|
removeFile(tmpFile)
|
||||||
str = compressImageStr(img)
|
|
||||||
}
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
actual fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream {
|
|
||||||
var img = image
|
// actual fun resizeImageToDataSize(image: ImageBitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream {
|
||||||
var stream = compressImageData(img, usePng)
|
// var img = image
|
||||||
while (stream.size() > maxDataSize) {
|
// var stream = compressImageData(img, usePng)
|
||||||
val ratio = sqrt(stream.size().toDouble() / maxDataSize.toDouble())
|
// while (stream.size() > maxDataSize) {
|
||||||
val clippedRatio = kotlin.math.min(ratio, 2.0)
|
// val ratio = sqrt(stream.size().toDouble() / maxDataSize.toDouble())
|
||||||
val width = (img.width.toDouble() / clippedRatio).toInt()
|
// val clippedRatio = kotlin.math.min(ratio, 2.0)
|
||||||
val height = img.height * width / img.width
|
// val width = (img.width.toDouble() / clippedRatio).toInt()
|
||||||
img = img.scale(width, height)
|
// val height = img.height * width / img.width
|
||||||
stream = compressImageData(img, usePng)
|
// img = img.scale(width, height)
|
||||||
}
|
// stream = compressImageData(img, usePng)
|
||||||
return stream
|
// }
|
||||||
}
|
// return stream
|
||||||
|
// }
|
||||||
|
|
||||||
actual fun cropToSquare(image: ImageBitmap): ImageBitmap {
|
actual fun cropToSquare(image: ImageBitmap): ImageBitmap {
|
||||||
var xOffset = 0
|
var xOffset = 0
|
||||||
@@ -81,17 +83,17 @@ actual fun cropToSquare(image: ImageBitmap): ImageBitmap {
|
|||||||
return croppedImage
|
return croppedImage
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun compressImageStr(bitmap: ImageBitmap): String {
|
// actual fun compressImageStr(bitmap: ImageBitmap): String {
|
||||||
val usePng = bitmap.hasAlpha()
|
// val usePng = bitmap.hasAlpha()
|
||||||
val ext = if (usePng) "png" else "jpg"
|
// val ext = if (usePng) "png" else "jpg"
|
||||||
return try {
|
// return try {
|
||||||
val encoded = Base64.getEncoder().encodeToString(compressImageData(bitmap, usePng).toByteArray())
|
// val encoded = Base64.getEncoder().encodeToString(compressImageData(bitmap, usePng).toByteArray())
|
||||||
"data:image/$ext;base64,$encoded"
|
// "data:image/$ext;base64,$encoded"
|
||||||
} catch (e: Exception) {
|
// } catch (e: Exception) {
|
||||||
Log.e(TAG, "resizeImageToStrSize error: $e")
|
// Log.e(TAG, "resizeImageToStrSize error: $e")
|
||||||
throw e
|
// throw e
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
actual fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream {
|
actual fun compressImageData(bitmap: ImageBitmap, usePng: Boolean): ByteArrayOutputStream {
|
||||||
val writer = ImageIO.getImageWritersByFormatName(if (usePng) "png" else "jpg").next()
|
val writer = ImageIO.getImageWritersByFormatName(if (usePng) "png" else "jpg").next()
|
||||||
|
|||||||
+7
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
|||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/simplex-chat/simplexmq.git
|
location: https://github.com/simplex-chat/simplexmq.git
|
||||||
tag: 79e9447b73cc315ce35042b0a5f210c07ea39b07
|
tag: 0a827307d666de819d5cef17f70a78be5cd0e410
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
@@ -63,3 +63,9 @@ source-repository-package
|
|||||||
location: https://github.com/simplex-chat/wai.git
|
location: https://github.com/simplex-chat/wai.git
|
||||||
tag: 2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0
|
tag: 2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0
|
||||||
subdir: warp
|
subdir: warp
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://gitlab.com/dpwiz/hs-jpeg-turbo
|
||||||
|
tag: d2844e00e7834124e27171cde21cf280d6772aa8
|
||||||
|
subdir: JuicyPixels-jpeg-turbo jpeg-turbo
|
||||||
|
|||||||
Generated
+281
-469
@@ -16,21 +16,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"blank": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1625557891,
|
|
||||||
"narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=",
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "blank",
|
|
||||||
"rev": "5a5d2684073d9f563072ed07c871d577a6c614a8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "blank",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cabal-32": {
|
"cabal-32": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -98,64 +83,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devshell": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1663445644,
|
|
||||||
"narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "devshell",
|
|
||||||
"rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "devshell",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dmerge": {
|
|
||||||
"inputs": {
|
|
||||||
"nixlib": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"yants": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"yants"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1659548052,
|
|
||||||
"narHash": "sha256-fzI2gp1skGA8mQo/FBFrUAtY0GQkAIAaV/V127TJPyY=",
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "data-merge",
|
|
||||||
"rev": "d160d18ce7b1a45b88344aa3f13ed1163954b497",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "data-merge",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -173,74 +100,34 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat_2": {
|
"flake-parts": {
|
||||||
"flake": false,
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1650374568,
|
"lastModified": 1698579227,
|
||||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
"narHash": "sha256-KVWjFZky+gRuWennKsbo6cWyo7c/z/VgCte5pR9pEKg=",
|
||||||
"owner": "edolstra",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-parts",
|
||||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
"rev": "f76e870d64779109e41370848074ac4eaa1606ec",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "edolstra",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-parts",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"locked": {
|
"inputs": {
|
||||||
"lastModified": 1676283394,
|
"systems": "systems"
|
||||||
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
|
|
||||||
"type": "github"
|
|
||||||
},
|
},
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_2": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667395993,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1653893745,
|
|
||||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1659877975,
|
|
||||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -266,33 +153,51 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gomod2nix": {
|
"ghc98X": {
|
||||||
"inputs": {
|
"flake": false,
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"utils": "utils"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1655245309,
|
"lastModified": 1715066704,
|
||||||
"narHash": "sha256-d/YPoQ/vFn1+GTmSdvbSBSTOai61FONxB4+Lt6w/IVI=",
|
"narHash": "sha256-F0EVR8x/fcpj1st+hz96Wdsz5uwVIOziGKAwRxLOYJw=",
|
||||||
"owner": "tweag",
|
"ref": "ghc-9.8",
|
||||||
"repo": "gomod2nix",
|
"rev": "78a253543d466ac511a1664a3e6aff032ca684d5",
|
||||||
"rev": "40d32f82fc60d66402eb0972e6e368aeab3faf58",
|
"revCount": 61757,
|
||||||
"type": "github"
|
"submodules": true,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/ghc/ghc"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "tweag",
|
"ref": "ghc-9.8",
|
||||||
"repo": "gomod2nix",
|
"submodules": true,
|
||||||
"type": "github"
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/ghc/ghc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ghc99": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1726585445,
|
||||||
|
"narHash": "sha256-IdwQBex4boY6s0Plj5+ixf36rfYSUyMdTWrztKvZH30=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "7fd9e5e29ab54eb406880077463e8552e2ddd39a",
|
||||||
|
"revCount": 67238,
|
||||||
|
"submodules": true,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/ghc/ghc"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"submodules": true,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/ghc/ghc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hackage": {
|
"hackage": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702340598,
|
"lastModified": 1702513363,
|
||||||
"narHash": "sha256-CC0HI+6iKPtH+8r/ZfcpW5v/OYvL7zMwpr0xfkXV1zU=",
|
"narHash": "sha256-kloro9uEe8aYhPMoMjVNq2rfrXNgMOZhOPwVH5DH2K0=",
|
||||||
"owner": "input-output-hk",
|
"owner": "input-output-hk",
|
||||||
"repo": "hackage.nix",
|
"repo": "hackage.nix",
|
||||||
"rev": "24617c569995e38bf3b83b48eec6628a50fdb4fb",
|
"rev": "a9d931d0398da67846fa257922a924829233cb91",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -309,33 +214,43 @@
|
|||||||
"cabal-36": "cabal-36",
|
"cabal-36": "cabal-36",
|
||||||
"cardano-shell": "cardano-shell",
|
"cardano-shell": "cardano-shell",
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils_2",
|
|
||||||
"ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
|
"ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
|
||||||
|
"ghc98X": "ghc98X",
|
||||||
|
"ghc99": "ghc99",
|
||||||
"hackage": [
|
"hackage": [
|
||||||
"hackage"
|
"hackage"
|
||||||
],
|
],
|
||||||
|
"hls-1.10": "hls-1.10",
|
||||||
|
"hls-2.0": "hls-2.0",
|
||||||
|
"hls-2.2": "hls-2.2",
|
||||||
|
"hls-2.3": "hls-2.3",
|
||||||
|
"hls-2.4": "hls-2.4",
|
||||||
|
"hls-2.5": "hls-2.5",
|
||||||
|
"hls-2.6": "hls-2.6",
|
||||||
"hpc-coveralls": "hpc-coveralls",
|
"hpc-coveralls": "hpc-coveralls",
|
||||||
"hydra": "hydra",
|
"hydra": "hydra",
|
||||||
"iserv-proxy": "iserv-proxy",
|
"iserv-proxy": "iserv-proxy",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"haskellNix",
|
||||||
|
"nixpkgs-unstable"
|
||||||
],
|
],
|
||||||
"nixpkgs-2003": "nixpkgs-2003",
|
"nixpkgs-2003": "nixpkgs-2003",
|
||||||
"nixpkgs-2105": "nixpkgs-2105",
|
"nixpkgs-2105": "nixpkgs-2105",
|
||||||
"nixpkgs-2111": "nixpkgs-2111",
|
"nixpkgs-2111": "nixpkgs-2111",
|
||||||
"nixpkgs-2205": "nixpkgs-2205",
|
"nixpkgs-2205": "nixpkgs-2205",
|
||||||
"nixpkgs-2211": "nixpkgs-2211",
|
"nixpkgs-2211": "nixpkgs-2211",
|
||||||
|
"nixpkgs-2305": "nixpkgs-2305",
|
||||||
|
"nixpkgs-2311": "nixpkgs-2311",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
"old-ghc-nix": "old-ghc-nix",
|
"old-ghc-nix": "old-ghc-nix",
|
||||||
"stackage": "stackage",
|
"stackage": "stackage"
|
||||||
"tullia": "tullia"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1677975916,
|
"lastModified": 1705833500,
|
||||||
"narHash": "sha256-dbe8lEEPyfzjdRwpePClv7J9p9lQg7BwbBqAMCw4RLw=",
|
"narHash": "sha256-rUIr6JNbCedt1g4gVYVvE9t0oFU6FUspCA0DS5cA8Bg=",
|
||||||
"owner": "input-output-hk",
|
"owner": "input-output-hk",
|
||||||
"repo": "haskell.nix",
|
"repo": "haskell.nix",
|
||||||
"rev": "ab5efd87ce3fd8ade38a01d97693d29a4f1ae7e4",
|
"rev": "d0c35e75cbbc6858770af42ac32b0b85495fbd71",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -345,6 +260,125 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hls-1.10": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1680000865,
|
||||||
|
"narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "1.10.0.0",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.0": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687698105,
|
||||||
|
"narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "783905f211ac63edf982dd1889c671653327e441",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.0.0.1",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.2": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1693064058,
|
||||||
|
"narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.2.0.0",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.3": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1695910642,
|
||||||
|
"narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.3.0.0",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.4": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1699862708,
|
||||||
|
"narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.4.0.1",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.5": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701080174,
|
||||||
|
"narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "27f8c3d3892e38edaef5bea3870161815c4d014c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.5.0.0",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hls-2.6": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705325287,
|
||||||
|
"narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=",
|
||||||
|
"owner": "haskell",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "haskell",
|
||||||
|
"ref": "2.6.0.0",
|
||||||
|
"repo": "haskell-language-server",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hpc-coveralls": {
|
"hpc-coveralls": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -384,37 +418,14 @@
|
|||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"incl": {
|
|
||||||
"inputs": {
|
|
||||||
"nixlib": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1669263024,
|
|
||||||
"narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=",
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "incl",
|
|
||||||
"rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "incl",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"iserv-proxy": {
|
"iserv-proxy": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1670983692,
|
"lastModified": 1707968597,
|
||||||
"narHash": "sha256-avLo34JnI9HNyOuauK5R69usJm+GfW3MlyGlYxZhTgY=",
|
"narHash": "sha256-C53NqToxl+n9s1pQ0iLtiH6P5vX3rM+NW/mFt4Ykpsk=",
|
||||||
"ref": "hkm/remote-iserv",
|
"ref": "hkm/remote-iserv",
|
||||||
"rev": "50d0abb3317ac439a4e7495b185a64af9b7b9300",
|
"rev": "1b7f8aeb37bbc7c00f04e44d9379aa15a4409e8b",
|
||||||
"revCount": 10,
|
"revCount": 18,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
|
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
|
||||||
},
|
},
|
||||||
@@ -440,32 +451,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"n2c": {
|
"mac2ios": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": [
|
"flake-parts": "flake-parts",
|
||||||
"haskellNix",
|
"nixpkgs": "nixpkgs_2"
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1665039323,
|
"lastModified": 1699767871,
|
||||||
"narHash": "sha256-SAh3ZjFGsaCI8FRzXQyp56qcGdAqgKEfJWPCQ0Sr7tQ=",
|
"narHash": "sha256-kxeCUfwC/Vgh2FvVMlBUq0eVx1JvfHyN+5MPKUik9mE=",
|
||||||
"owner": "nlewo",
|
"owner": "zw3rk",
|
||||||
"repo": "nix2container",
|
"repo": "mobile-core-tools",
|
||||||
"rev": "b008fe329ffb59b67bf9e7b08ede6ee792f2741a",
|
"rev": "4dcb77d5ea896d749381806dfab5358851b08951",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nlewo",
|
"owner": "zw3rk",
|
||||||
"repo": "nix2container",
|
"repo": "mobile-core-tools",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -490,95 +491,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nix-nomad": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat_2",
|
|
||||||
"flake-utils": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"nix2container",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"gomod2nix": "gomod2nix",
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1658277770,
|
|
||||||
"narHash": "sha256-T/PgG3wUn8Z2rnzfxf2VqlR1CBjInPE0l1yVzXxPnt0=",
|
|
||||||
"owner": "tristanpemble",
|
|
||||||
"repo": "nix-nomad",
|
|
||||||
"rev": "054adcbdd0a836ae1c20951b67ed549131fd2d70",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "tristanpemble",
|
|
||||||
"repo": "nix-nomad",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix2container": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_3",
|
|
||||||
"nixpkgs": "nixpkgs_3"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1658567952,
|
|
||||||
"narHash": "sha256-XZ4ETYAMU7XcpEeAFP3NOl9yDXNuZAen/aIJ84G+VgA=",
|
|
||||||
"owner": "nlewo",
|
|
||||||
"repo": "nix2container",
|
|
||||||
"rev": "60bb43d405991c1378baf15a40b5811a53e32ffa",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nlewo",
|
|
||||||
"repo": "nix2container",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixago": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"nixago-exts": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"blank"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1661824785,
|
|
||||||
"narHash": "sha256-/PnwdWoO/JugJZHtDUioQp3uRiWeXHUdgvoyNbXesz8=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixago",
|
|
||||||
"rev": "8c1f9e5f1578d4b2ea989f618588d62a335083c3",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixago",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1657693803,
|
"lastModified": 1657693803,
|
||||||
@@ -645,11 +557,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-2205": {
|
"nixpkgs-2205": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1672580127,
|
"lastModified": 1685573264,
|
||||||
"narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=",
|
"narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0874168639713f547c05947c76124f78441ea46c",
|
"rev": "380be19fbd2d9079f677978361792cb25e8a3635",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -661,11 +573,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-2211": {
|
"nixpkgs-2211": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1675730325,
|
"lastModified": 1688392541,
|
||||||
"narHash": "sha256-uNvD7fzO5hNlltNQUAFBPlcEjNG5Gkbhl/ROiX+GZU4=",
|
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b7ce17b1ebf600a72178f6302c77b6382d09323f",
|
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -675,6 +587,56 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-2305": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705033721,
|
||||||
|
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-23.05-darwin",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-2311": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719957072,
|
||||||
|
"narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "7144d6241f02d171d25fba3edeaf15e0f2592105",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-23.11-darwin",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "lib",
|
||||||
|
"lastModified": 1696019113,
|
||||||
|
"narHash": "sha256-X3+DKYWJm93DRSdC5M6K5hLqzSya9BjibtBsuARoPco=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "f5892ddac112a1e9b3612c39af1b72987ee5783a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "lib",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs-regression": {
|
"nixpkgs-regression": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1643052045,
|
"lastModified": 1643052045,
|
||||||
@@ -693,98 +655,36 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1675758091,
|
"lastModified": 1694822471,
|
||||||
"narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=",
|
"narHash": "sha256-6fSDCj++lZVMZlyqOe9SIOL8tYSBz1bI8acwovRwoX8=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87",
|
"rev": "47585496bcb13fb72e4a90daeea2f434e2501998",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
|
"rev": "47585496bcb13fb72e4a90daeea2f434e2501998",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1653581809,
|
"lastModified": 1698434055,
|
||||||
"narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=",
|
"narHash": "sha256-Phxi5mUKSoL7A0IYUiYtkI9e8NcGaaV5PJEaJApU1Ko=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "83658b28fe638a170a19b8933aa008b30640fbd1",
|
"rev": "1a3c95e3b23b3cdb26750621c08cc2f1560cb883",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-23.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1654807842,
|
|
||||||
"narHash": "sha256-ADymZpr6LuTEBXcy6RtFHcUZdjKTBRTMYwu19WOx17E=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "fc909087cc3386955f21b4665731dbdaceefb1d8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1665087388,
|
|
||||||
"narHash": "sha256-FZFPuW9NWHJteATOf79rZfwfRn5fE0wi9kRzvGfDHPA=",
|
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "95fda953f6db2e9496d2682c4fc7b82f959878f7",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_5": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1676726892,
|
|
||||||
"narHash": "sha256-M7OYVR6dKmzmlebIjybFf3l18S2uur8lMyWWnHQooLY=",
|
|
||||||
"owner": "angerman",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "729469087592bdea58b360de59dadf6d58714c42",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "angerman",
|
|
||||||
"ref": "release-22.11",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nosys": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667881534,
|
|
||||||
"narHash": "sha256-FhwJ15uPLRsvaxtt/bNuqE/ykMpNAPF0upozFKhTtXM=",
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "nosys",
|
|
||||||
"rev": "2d0d5207f6a230e9d0f660903f8db9807b54814f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "nosys",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"old-ghc-nix": {
|
"old-ghc-nix": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -807,17 +707,21 @@
|
|||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"hackage": "hackage",
|
"hackage": "hackage",
|
||||||
"haskellNix": "haskellNix",
|
"haskellNix": "haskellNix",
|
||||||
"nixpkgs": "nixpkgs_5"
|
"mac2ios": "mac2ios",
|
||||||
|
"nixpkgs": [
|
||||||
|
"haskellNix",
|
||||||
|
"nixpkgs-2305"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stackage": {
|
"stackage": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1677888571,
|
"lastModified": 1726532152,
|
||||||
"narHash": "sha256-YkhRNOaN6QVagZo1cfykYV8KqkI8/q6r2F5+jypOma4=",
|
"narHash": "sha256-LRXbVY3M2S8uQWdwd2zZrsnVPEvt2GxaHGoy8EFFdJA=",
|
||||||
"owner": "input-output-hk",
|
"owner": "input-output-hk",
|
||||||
"repo": "stackage.nix",
|
"repo": "stackage.nix",
|
||||||
"rev": "cb50e6fabdfb2d7e655059039012ad0623f06a27",
|
"rev": "c77b3530cebad603812cb111c6f64968c2d2337d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -826,110 +730,18 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"std": {
|
"systems": {
|
||||||
"inputs": {
|
|
||||||
"arion": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"blank"
|
|
||||||
],
|
|
||||||
"blank": "blank",
|
|
||||||
"devshell": "devshell",
|
|
||||||
"dmerge": "dmerge",
|
|
||||||
"flake-utils": "flake-utils_4",
|
|
||||||
"incl": "incl",
|
|
||||||
"makes": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"blank"
|
|
||||||
],
|
|
||||||
"microvm": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"blank"
|
|
||||||
],
|
|
||||||
"n2c": "n2c",
|
|
||||||
"nixago": "nixago",
|
|
||||||
"nixpkgs": "nixpkgs_4",
|
|
||||||
"nosys": "nosys",
|
|
||||||
"yants": "yants"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1674526466,
|
"lastModified": 1681028828,
|
||||||
"narHash": "sha256-tMTaS0bqLx6VJ+K+ZT6xqsXNpzvSXJTmogkraBGzymg=",
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
"owner": "divnix",
|
"owner": "nix-systems",
|
||||||
"repo": "std",
|
"repo": "default",
|
||||||
"rev": "516387e3d8d059b50e742a2ff1909ed3c8f82826",
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "divnix",
|
"owner": "nix-systems",
|
||||||
"repo": "std",
|
"repo": "default",
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tullia": {
|
|
||||||
"inputs": {
|
|
||||||
"nix-nomad": "nix-nomad",
|
|
||||||
"nix2container": "nix2container",
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"std": "std"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1675695930,
|
|
||||||
"narHash": "sha256-B7rEZ/DBUMlK1AcJ9ajnAPPxqXY6zW2SBX+51bZV0Ac=",
|
|
||||||
"owner": "input-output-hk",
|
|
||||||
"repo": "tullia",
|
|
||||||
"rev": "621365f2c725608f381b3ad5b57afef389fd4c31",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "input-output-hk",
|
|
||||||
"repo": "tullia",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"utils": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1653893745,
|
|
||||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yants": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"haskellNix",
|
|
||||||
"tullia",
|
|
||||||
"std",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667096281,
|
|
||||||
"narHash": "sha256-wRRec6ze0gJHmGn6m57/zhz/Kdvp9HS4Nl5fkQ+uIuA=",
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "yants",
|
|
||||||
"rev": "d18f356ec25cb94dc9c275870c3a7927a10f8c3c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "divnix",
|
|
||||||
"repo": "yants",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
description = "nix flake for simplex-chat";
|
description = "nix flake for simplex-chat";
|
||||||
inputs.nixpkgs.url = "github:angerman/nixpkgs/release-22.11";
|
|
||||||
inputs.haskellNix.url = "github:input-output-hk/haskell.nix/armv7a";
|
inputs.haskellNix.url = "github:input-output-hk/haskell.nix/armv7a";
|
||||||
inputs.haskellNix.inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "haskellNix/nixpkgs-2305";
|
||||||
|
inputs.mac2ios.url = "github:zw3rk/mobile-core-tools";
|
||||||
inputs.hackage = {
|
inputs.hackage = {
|
||||||
url = "github:input-output-hk/hackage.nix";
|
url = "github:input-output-hk/hackage.nix";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
inputs.haskellNix.inputs.hackage.follows = "hackage";
|
inputs.haskellNix.inputs.hackage.follows = "hackage";
|
||||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
outputs = { self, haskellNix, nixpkgs, flake-utils, ... }:
|
outputs = { self, haskellNix, nixpkgs, flake-utils, mac2ios, ... }:
|
||||||
let systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; in
|
let systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; in
|
||||||
flake-utils.lib.eachSystem systems (system:
|
flake-utils.lib.eachSystem systems (system:
|
||||||
# this android26 overlay makes the pkgsCross.{aarch64-android,armv7a-android-prebuilt} to set stdVer to 26 (Android 8).
|
# this android26 overlay makes the pkgsCross.{aarch64-android,armv7a-android-prebuilt} to set stdVer to 26 (Android 8).
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
# `appendOverlays` with a singleton is identical to `extend`.
|
# `appendOverlays` with a singleton is identical to `extend`.
|
||||||
let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in
|
let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in
|
||||||
let drv' = { extra-modules, pkgs', ... }: pkgs'.haskell-nix.project {
|
let drv' = { extra-modules, pkgs', ... }: pkgs'.haskell-nix.project {
|
||||||
compiler-nix-name = "ghc8107";
|
compiler-nix-name = "ghc963";
|
||||||
index-state = "2023-12-12T00:00:00Z";
|
index-state = "2023-12-12T00:00:00Z";
|
||||||
# We need this, to specify we want the cabal project.
|
# We need this, to specify we want the cabal project.
|
||||||
# If the stack.yaml was dropped, this would not be necessary.
|
# If the stack.yaml was dropped, this would not be necessary.
|
||||||
@@ -40,9 +40,12 @@
|
|||||||
src = ./.;
|
src = ./.;
|
||||||
};
|
};
|
||||||
sha256map = import ./scripts/nix/sha256map.nix;
|
sha256map = import ./scripts/nix/sha256map.nix;
|
||||||
modules = [{
|
modules = [
|
||||||
|
({ pkgs, lib, ...}: lib.mkIf (!pkgs.stdenv.hostPlatform.isWindows) {
|
||||||
|
# This patch adds `dl` as an extra-library to direct-sqlciper, which is needed
|
||||||
|
# on pretty much all unix platforms, but then blows up on windows m(
|
||||||
packages.direct-sqlcipher.patches = [ ./scripts/nix/direct-sqlcipher-2.3.27.patch ];
|
packages.direct-sqlcipher.patches = [ ./scripts/nix/direct-sqlcipher-2.3.27.patch ];
|
||||||
}
|
})
|
||||||
({ pkgs,lib, ... }: lib.mkIf (pkgs.stdenv.hostPlatform.isAndroid) {
|
({ pkgs,lib, ... }: lib.mkIf (pkgs.stdenv.hostPlatform.isAndroid) {
|
||||||
packages.simplex-chat.components.library.ghcOptions = [ "-pie" ];
|
packages.simplex-chat.components.library.ghcOptions = [ "-pie" ];
|
||||||
})] ++ extra-modules;
|
})] ++ extra-modules;
|
||||||
@@ -64,6 +67,9 @@
|
|||||||
}); in
|
}); in
|
||||||
let iosPostInstall = bundleName: ''
|
let iosPostInstall = bundleName: ''
|
||||||
${pkgs.tree}/bin/tree $out
|
${pkgs.tree}/bin/tree $out
|
||||||
|
mkdir tmp
|
||||||
|
find ./dist -name "libHS*-ghc*.a" -exec cp {} tmp \;
|
||||||
|
(cd tmp; ${pkgs.tree}/bin/tree .; ar x libHS*.a; for o in *.o; do if /usr/bin/otool -xv $o|grep ldadd ; then echo $o; fi; done; cd ..; rm -fR tmp)
|
||||||
mkdir -p $out/_pkg
|
mkdir -p $out/_pkg
|
||||||
# copy over includes, we might want those, but maybe not.
|
# copy over includes, we might want those, but maybe not.
|
||||||
# cp -r $out/lib/*/*/include $out/_pkg/
|
# cp -r $out/lib/*/*/include $out/_pkg/
|
||||||
@@ -74,6 +80,18 @@
|
|||||||
find ${pkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
|
find ${pkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
|
||||||
# There is no static libc
|
# There is no static libc
|
||||||
${pkgs.tree}/bin/tree $out/_pkg
|
${pkgs.tree}/bin/tree $out/_pkg
|
||||||
|
for pkg in $out/_pkg/*.a; do
|
||||||
|
chmod +w $pkg
|
||||||
|
${mac2ios.packages.${system}.mac2ios}/bin/mac2ios $pkg
|
||||||
|
chmod -w $pkg
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir tmp
|
||||||
|
find $out/_pkg -name "libHS*-ghc*.a" -exec cp {} tmp \;
|
||||||
|
(cd tmp; ${pkgs.tree}/bin/tree .; ar x libHS*.a; for o in *.o; do if /usr/bin/otool -xv $o|grep ldadd ; then echo $o; fi; done; cd ..; rm -fR tmp)
|
||||||
|
|
||||||
|
sha256sum $out/_pkg/*.a
|
||||||
|
|
||||||
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${bundleName}.zip *)
|
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${bundleName}.zip *)
|
||||||
rm -fR $out/_pkg
|
rm -fR $out/_pkg
|
||||||
mkdir -p $out/nix-support
|
mkdir -p $out/nix-support
|
||||||
@@ -119,13 +137,151 @@
|
|||||||
hardeningDisable = [ "fortify" ];
|
hardeningDisable = [ "fortify" ];
|
||||||
}
|
}
|
||||||
);in {
|
);in {
|
||||||
|
# STATIC x86_64-linux
|
||||||
"${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat;
|
"${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat;
|
||||||
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl32).simplex-chat.components.exes.simplex-chat;
|
# STATIC i686-linux
|
||||||
|
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv' {
|
||||||
|
pkgs' = pkgs.pkgsCross.musl32;
|
||||||
|
extra-modules = [{
|
||||||
|
# 32 bit patches
|
||||||
|
packages.basement.patches = [
|
||||||
|
./scripts/nix/basement-pr-573.patch
|
||||||
|
];
|
||||||
|
packages.memory.patches = [
|
||||||
|
./scripts/nix/memory-pr-99.patch
|
||||||
|
];
|
||||||
|
}];
|
||||||
|
}).simplex-chat.components.exes.simplex-chat;
|
||||||
|
# WINDOWS x86_64-mingwW64
|
||||||
|
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:exe:simplex-chat" = (drv' {
|
||||||
|
pkgs' = pkgs.pkgsCross.mingwW64;
|
||||||
|
extra-modules = [{
|
||||||
|
packages.direct-sqlcipher.flags.openssl = true;
|
||||||
|
packages.bitvec.flags.simd = false;
|
||||||
|
packages.direct-sqlcipher.patches = [
|
||||||
|
./scripts/nix/direct-sqlcipher-2.3.27-win.patch
|
||||||
|
];
|
||||||
|
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
||||||
|
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
|
||||||
|
];
|
||||||
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
|
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
|
||||||
|
];
|
||||||
|
packages.unix-time.postPatch = ''
|
||||||
|
sed -i 's/mingwex//g' unix-time.cabal
|
||||||
|
'';
|
||||||
|
}];
|
||||||
|
}).simplex-chat.components.exes.simplex-chat.override {
|
||||||
|
postInstall = ''
|
||||||
|
set -x
|
||||||
|
${pkgs.tree}/bin/tree $out
|
||||||
|
mkdir -p $out/_pkg
|
||||||
|
cp $out/bin/* $out/_pkg
|
||||||
|
${pkgs.tree}/bin/tree $out/_pkg
|
||||||
|
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${pkgs.pkgsCross.mingwW64.hostPlatform.system}-simplex-chat.zip *)
|
||||||
|
rm -fR $out/_pkg
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
|
> $out/nix-support/hydra-build-products
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:lib:simplex-chat" = (drv' rec {
|
||||||
|
pkgs' = pkgs.pkgsCross.mingwW64;
|
||||||
|
extra-modules = [{
|
||||||
|
packages.direct-sqlcipher.flags.openssl = true;
|
||||||
|
# simd will try to read __cpu_model, which we don't expose
|
||||||
|
# from the rts (yet!).
|
||||||
|
packages.bitvec.flags.simd = false;
|
||||||
|
packages.direct-sqlcipher.patches = [
|
||||||
|
./scripts/nix/direct-sqlcipher-2.3.27-win.patch
|
||||||
|
];
|
||||||
|
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
||||||
|
pkgs.pkgsCross.mingwW64.openssl
|
||||||
|
];
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
|
packages.simplexmq.flags.client_library = true;
|
||||||
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
|
pkgs.pkgsCross.mingwW64.openssl
|
||||||
|
];
|
||||||
|
packages.unix-time.postPatch = ''
|
||||||
|
sed -i 's/mingwex//g' unix-time.cabal
|
||||||
|
'';
|
||||||
|
}];
|
||||||
|
}).simplex-chat.components.library
|
||||||
|
.override (p: {
|
||||||
|
# enableShared = false;
|
||||||
|
setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [
|
||||||
|
"-shared"
|
||||||
|
"-threaded"
|
||||||
|
"-o" "libsimplex.dll"
|
||||||
|
# "-optl-lHSrts_thr"
|
||||||
|
"-optl-lffi"
|
||||||
|
# "-optl-static-libgcc"
|
||||||
|
# We can't do -optl-static-libstdc++ with gcc. g++ might
|
||||||
|
# but then we are chaning the compiler altogether.
|
||||||
|
"${./libsimplex.dll.def}"
|
||||||
|
];
|
||||||
|
postInstall = ''
|
||||||
|
set -x
|
||||||
|
function deps() {
|
||||||
|
${pkgs.binutils}/bin/strings "$1" | grep '.\.dll'|grep -v -E 'Winsock|ADVAPI32|dbghelp|KERNEL32|msvcrt|ntdll|ole32|RPCRT4|SHELL32|USER32|WINMM|WS2_32|kernel32|GDI32'|grep -v "$1"
|
||||||
|
}
|
||||||
|
${pkgs.tree}/bin/tree $out
|
||||||
|
mkdir -p $out/_pkg
|
||||||
|
cp libsimplex.dll $out/_pkg
|
||||||
|
cp libsimplex.dll.a $out/_pkg
|
||||||
|
mkdir $out/libs
|
||||||
|
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.openssl} -name "*.dll" -exec cp {} $out/libs \;
|
||||||
|
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.libffi} -name "*.dll" -exec cp {} $out/libs \;
|
||||||
|
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.gmp} -name "*.dll" -exec cp {} $out/libs \;
|
||||||
|
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.stdenv.cc.cc} -name "*.dll" -exec cp {} $out/libs \;
|
||||||
|
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.windows.mcfgthreads} -name "*.dll" -exec cp {} $out/libs \;
|
||||||
|
|
||||||
|
pushd $out/_pkg
|
||||||
|
function copyDeps() {
|
||||||
|
for dep in $(deps "$1"); do
|
||||||
|
if [ ! -f "$dep" ]; then
|
||||||
|
if [ ! -f ../libs/"$dep" ]; then
|
||||||
|
echo "WARN: $1 -> $dep not found!"
|
||||||
|
else
|
||||||
|
cp ../libs/"$dep" .
|
||||||
|
copyDeps "$dep"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
copyDeps libsimplex.dll
|
||||||
|
popd
|
||||||
|
${pkgs.tree}/bin/tree $out/_pkg
|
||||||
|
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-${pkgs.pkgsCross.mingwW64.hostPlatform.system}-libsimplex.zip *)
|
||||||
|
rm -fR $out/_pkg
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
|
> $out/nix-support/hydra-build-products
|
||||||
|
'';
|
||||||
|
});
|
||||||
# "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat;
|
# "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat;
|
||||||
|
|
||||||
|
# STATIC aarch64-linux
|
||||||
"${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat;
|
"${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat;
|
||||||
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override {
|
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override (p: {
|
||||||
smallAddressSpace = true; enableShared = false;
|
smallAddressSpace = true;
|
||||||
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
|
# we won't want -dyamic (see aarch64-android:lib:simplex-chat)
|
||||||
|
enableShared = false;
|
||||||
|
# we also do not want to have any dependencies listed (especially no rts!)
|
||||||
|
enableStatic = false;
|
||||||
|
|
||||||
|
# This used to work with 8.10.7...
|
||||||
|
# setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
|
||||||
|
# ... but now with 9.6+
|
||||||
|
# we have to do the -shared thing by hand.
|
||||||
|
postBuild = ''
|
||||||
|
armv7a-unknown-linux-androideabi-ghc -shared -o libsupport.so \
|
||||||
|
-optl-Wl,-u,setLineBuffering \
|
||||||
|
-optl-Wl,-u,pipe_std_to_socket \
|
||||||
|
dist/build/*.a
|
||||||
|
'';
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
|
|
||||||
mkdir -p $out/_pkg
|
mkdir -p $out/_pkg
|
||||||
@@ -138,14 +294,29 @@
|
|||||||
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
> $out/nix-support/hydra-build-products
|
> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
};
|
});
|
||||||
"aarch64-android:lib:support" = (drv androidPkgs).android-support.components.library.override {
|
# The android-support package is at
|
||||||
smallAddressSpace = true; enableShared = false;
|
# https://github.com/simplex-chat/android-support
|
||||||
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
|
"aarch64-android:lib:support" = (drv androidPkgs).android-support.components.library.override (p: {
|
||||||
|
smallAddressSpace = true;
|
||||||
|
# no -dynamic
|
||||||
|
enableShared = false;
|
||||||
|
# but also no -staticlib
|
||||||
|
enableStatic = false;
|
||||||
|
|
||||||
|
# we have to do the -shared thing by hand.
|
||||||
|
postBuild = ''
|
||||||
|
aarch64-unknown-linux-android-ghc -shared -o libsupport.so \
|
||||||
|
-optl-Wl,-u,setLineBuffering \
|
||||||
|
-optl-Wl,-u,pipe_std_to_socket \
|
||||||
|
dist/build/*.a
|
||||||
|
'';
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
|
|
||||||
mkdir -p $out/_pkg
|
mkdir -p $out/_pkg
|
||||||
cp libsupport.so $out/_pkg
|
cp libsupport.so $out/_pkg
|
||||||
|
ls -lah $out/_pkg/*
|
||||||
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
|
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
|
||||||
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-aarch64-android-libsupport.zip *)
|
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-aarch64-android-libsupport.zip *)
|
||||||
rm -fR $out/_pkg
|
rm -fR $out/_pkg
|
||||||
@@ -154,10 +325,11 @@
|
|||||||
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
> $out/nix-support/hydra-build-products
|
> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
};
|
});
|
||||||
"armv7a-android:lib:simplex-chat" = (drv' {
|
"armv7a-android:lib:simplex-chat" = (drv' {
|
||||||
pkgs' = android32Pkgs;
|
pkgs' = android32Pkgs;
|
||||||
extra-modules = [{
|
extra-modules = [{
|
||||||
|
packages.text.flags.simdutf = false;
|
||||||
packages.direct-sqlcipher.flags.openssl = true;
|
packages.direct-sqlcipher.flags.openssl = true;
|
||||||
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
||||||
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
|
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
|
||||||
@@ -165,17 +337,63 @@
|
|||||||
packages.direct-sqlcipher.patches = [
|
packages.direct-sqlcipher.patches = [
|
||||||
./scripts/nix/direct-sqlcipher-android-log.patch
|
./scripts/nix/direct-sqlcipher-android-log.patch
|
||||||
];
|
];
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
|
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
|
||||||
];
|
];
|
||||||
|
# 32 bit patches
|
||||||
|
packages.basement.patches = [
|
||||||
|
./scripts/nix/basement-pr-573.patch
|
||||||
|
];
|
||||||
|
packages.memory.patches = [
|
||||||
|
./scripts/nix/memory-pr-99.patch
|
||||||
|
];
|
||||||
}];
|
}];
|
||||||
}).simplex-chat.components.library.override {
|
}).simplex-chat.components.library.override (p: {
|
||||||
smallAddressSpace = true; enableShared = false;
|
smallAddressSpace = true;
|
||||||
|
# we want -shared, but not -dyanmic, hence `enableShared = false`.
|
||||||
|
enableShared = false;
|
||||||
|
# we _do_ want rts, and other libs. Hence `enableStatic = true`.
|
||||||
|
enableStatic = true;
|
||||||
# for android we build a shared library, passing these arguments is a bit tricky, as
|
# for android we build a shared library, passing these arguments is a bit tricky, as
|
||||||
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
|
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
|
||||||
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
|
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
|
||||||
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
|
setupBuildFlags = p.component.setupBuildFlags
|
||||||
|
# flags to tell GHC we want to produce a -shared object, and we want to also link
|
||||||
|
# - the ffi library (ffi)
|
||||||
|
++ map (x: "--ghc-option=${x}") [
|
||||||
|
"-shared" "-o" "libsimplex.so"
|
||||||
|
"-threaded"
|
||||||
|
# "-debug"
|
||||||
|
"-optl-lffi"
|
||||||
|
]
|
||||||
|
# This is fairly idiotic. LLD will strip out foreign exported
|
||||||
|
# symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>`
|
||||||
|
# to ensure they stay in the produced library. Having them
|
||||||
|
# _undefined_ and _lazy_ (lld will tell with -y <sym> that the
|
||||||
|
# symbol is lazy), makes them _defined_. m(
|
||||||
|
++ map (sym: "--ghc-option=-optl-Wl,-u,${sym}") [
|
||||||
|
"chat_close_store"
|
||||||
|
"chat_decrypt_file"
|
||||||
|
"chat_decrypt_media"
|
||||||
|
"chat_encrypt_file"
|
||||||
|
"chat_encrypt_media"
|
||||||
|
"chat_migrate_init"
|
||||||
|
"chat_parse_markdown"
|
||||||
|
"chat_parse_server"
|
||||||
|
"chat_password_hash"
|
||||||
|
"chat_read_file"
|
||||||
|
"chat_recv_msg"
|
||||||
|
"chat_recv_msg_wait"
|
||||||
|
"chat_send_cmd"
|
||||||
|
"chat_send_remote_cmd"
|
||||||
|
"chat_valid_name"
|
||||||
|
"chat_json_length"
|
||||||
|
"chat_write_file"
|
||||||
|
"chat_write_image"
|
||||||
|
"chat_resize_image_to_str_size"
|
||||||
|
];
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
set -x
|
set -x
|
||||||
${pkgs.tree}/bin/tree $out
|
${pkgs.tree}/bin/tree $out
|
||||||
@@ -219,10 +437,11 @@
|
|||||||
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
> $out/nix-support/hydra-build-products
|
> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
};
|
});
|
||||||
"aarch64-android:lib:simplex-chat" = (drv' {
|
"aarch64-android:lib:simplex-chat" = (drv' {
|
||||||
pkgs' = androidPkgs;
|
pkgs' = androidPkgs;
|
||||||
extra-modules = [{
|
extra-modules = [{
|
||||||
|
packages.text.flags.simdutf = false;
|
||||||
packages.direct-sqlcipher.flags.openssl = true;
|
packages.direct-sqlcipher.flags.openssl = true;
|
||||||
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
|
||||||
(androidPkgs.openssl.override { static = true; })
|
(androidPkgs.openssl.override { static = true; })
|
||||||
@@ -230,17 +449,62 @@
|
|||||||
packages.direct-sqlcipher.patches = [
|
packages.direct-sqlcipher.patches = [
|
||||||
./scripts/nix/direct-sqlcipher-android-log.patch
|
./scripts/nix/direct-sqlcipher-android-log.patch
|
||||||
];
|
];
|
||||||
|
packages.jpeg-turbo.flags.static = true;
|
||||||
|
packages.jpeg-turbo.components.library.libs = pkgs.lib.mkForce [
|
||||||
|
(androidPkgs.libjpeg_turbo.override { enableStatic = true; })
|
||||||
|
];
|
||||||
|
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
(androidPkgs.openssl.override { static = true; })
|
(androidPkgs.openssl.override { static = true; })
|
||||||
];
|
];
|
||||||
}];
|
}];
|
||||||
}).simplex-chat.components.library.override {
|
}).simplex-chat.components.library.override (p: {
|
||||||
smallAddressSpace = true; enableShared = false;
|
smallAddressSpace = true;
|
||||||
|
# we do not want a dynamically linked object, even though we _do_
|
||||||
|
# want to produce a _shared_ object. But `shared` implied -dyanmic
|
||||||
|
# with cabal, so we disable and pass `-shared` explicitly.
|
||||||
|
enableShared = false;
|
||||||
|
# we do want static (e.g. pass all dependencies in, so we get -staticlib)
|
||||||
|
enableStatic = true;
|
||||||
# for android we build a shared library, passing these arguments is a bit tricky, as
|
# for android we build a shared library, passing these arguments is a bit tricky, as
|
||||||
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
|
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
|
||||||
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
|
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
|
||||||
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
|
setupBuildFlags = p.component.setupBuildFlags
|
||||||
|
# flags to tell GHC we want to produce a -shared object, and we want to also link
|
||||||
|
# - the ffi library (ffi)
|
||||||
|
++ map (x: "--ghc-option=${x}") [
|
||||||
|
"-shared" "-o" "libsimplex.so"
|
||||||
|
"-threaded"
|
||||||
|
# "-debug"
|
||||||
|
"-optl-lffi"
|
||||||
|
]
|
||||||
|
# This is fairly idiotic. LLD will strip out foreign exported
|
||||||
|
# symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>`
|
||||||
|
# to ensure they stay in the produced library. Having them
|
||||||
|
# _undefined_ and _lazy_ (lld will tell with -y <sym> that the
|
||||||
|
# symbol is lazy), makes them _defined_. m(
|
||||||
|
++ map (sym: "--ghc-option=-optl-Wl,-u,${sym}") [
|
||||||
|
"chat_close_store"
|
||||||
|
"chat_decrypt_file"
|
||||||
|
"chat_decrypt_media"
|
||||||
|
"chat_encrypt_file"
|
||||||
|
"chat_encrypt_media"
|
||||||
|
"chat_migrate_init"
|
||||||
|
"chat_parse_markdown"
|
||||||
|
"chat_parse_server"
|
||||||
|
"chat_password_hash"
|
||||||
|
"chat_read_file"
|
||||||
|
"chat_recv_msg"
|
||||||
|
"chat_recv_msg_wait"
|
||||||
|
"chat_send_cmd"
|
||||||
|
"chat_send_remote_cmd"
|
||||||
|
"chat_valid_name"
|
||||||
|
"chat_json_length"
|
||||||
|
"chat_write_file"
|
||||||
|
"chat_write_image"
|
||||||
|
"chat_resize_image_to_str_size"
|
||||||
|
];
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
set -x
|
set -x
|
||||||
${pkgs.tree}/bin/tree $out
|
${pkgs.tree}/bin/tree $out
|
||||||
@@ -284,7 +548,7 @@
|
|||||||
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
echo "file binary-dist \"$(echo $out/*.zip)\"" \
|
||||||
> $out/nix-support/hydra-build-products
|
> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
# builds for iOS and iOS simulator
|
# builds for iOS and iOS simulator
|
||||||
@@ -297,9 +561,11 @@
|
|||||||
packages.simplexmq.flags.swift = true;
|
packages.simplexmq.flags.swift = true;
|
||||||
packages.direct-sqlcipher.flags.commoncrypto = true;
|
packages.direct-sqlcipher.flags.commoncrypto = true;
|
||||||
packages.entropy.flags.DoNotGetEntropy = true;
|
packages.entropy.flags.DoNotGetEntropy = true;
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
(pkgs.openssl.override { static = true; })
|
# TODO: have a cross override for iOS, that sets this.
|
||||||
|
((pkgs.openssl.override { static = true; }).overrideDerivation (old: { CFLAGS = "-mcpu=apple-a7 -march=armv8-a+norcpc" ;}))
|
||||||
];
|
];
|
||||||
}];
|
}];
|
||||||
}).simplex-chat.components.library.override (
|
}).simplex-chat.components.library.override (
|
||||||
@@ -311,6 +577,7 @@
|
|||||||
extra-modules = [{
|
extra-modules = [{
|
||||||
packages.direct-sqlcipher.flags.commoncrypto = true;
|
packages.direct-sqlcipher.flags.commoncrypto = true;
|
||||||
packages.entropy.flags.DoNotGetEntropy = true;
|
packages.entropy.flags.DoNotGetEntropy = true;
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
((pkgs.openssl.override { static = true; }).overrideDerivation (old: { CFLAGS = "-mcpu=apple-a7 -march=armv8-a+norcpc" ;}))
|
((pkgs.openssl.override { static = true; }).overrideDerivation (old: { CFLAGS = "-mcpu=apple-a7 -march=armv8-a+norcpc" ;}))
|
||||||
@@ -329,6 +596,7 @@
|
|||||||
packages.simplexmq.flags.swift = true;
|
packages.simplexmq.flags.swift = true;
|
||||||
packages.direct-sqlcipher.flags.commoncrypto = true;
|
packages.direct-sqlcipher.flags.commoncrypto = true;
|
||||||
packages.entropy.flags.DoNotGetEntropy = true;
|
packages.entropy.flags.DoNotGetEntropy = true;
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
(pkgs.openssl.override { static = true; })
|
(pkgs.openssl.override { static = true; })
|
||||||
@@ -343,6 +611,7 @@
|
|||||||
extra-modules = [{
|
extra-modules = [{
|
||||||
packages.direct-sqlcipher.flags.commoncrypto = true;
|
packages.direct-sqlcipher.flags.commoncrypto = true;
|
||||||
packages.entropy.flags.DoNotGetEntropy = true;
|
packages.entropy.flags.DoNotGetEntropy = true;
|
||||||
|
packages."jpeg-turbo".flags.static = true;
|
||||||
packages.simplexmq.flags.client_library = true;
|
packages.simplexmq.flags.client_library = true;
|
||||||
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
|
||||||
(pkgs.openssl.override { static = true; })
|
(pkgs.openssl.override { static = true; })
|
||||||
|
|||||||
+3
-1
@@ -16,6 +16,8 @@ EXPORTS
|
|||||||
chat_encrypt_media
|
chat_encrypt_media
|
||||||
chat_decrypt_media
|
chat_decrypt_media
|
||||||
chat_write_file
|
chat_write_file
|
||||||
|
chat_write_image
|
||||||
chat_read_file
|
chat_read_file
|
||||||
chat_encrypt_file
|
chat_encrypt_file
|
||||||
chat_decrypt_file
|
chat_decrypt_file
|
||||||
|
chat_resize_image_to_str_size
|
||||||
@@ -52,6 +52,9 @@ dependencies:
|
|||||||
- unliftio-core == 0.2.*
|
- unliftio-core == 0.2.*
|
||||||
- uuid == 1.3.*
|
- uuid == 1.3.*
|
||||||
- zip == 2.0.*
|
- zip == 2.0.*
|
||||||
|
- JuicyPixels
|
||||||
|
- JuicyPixels-jpeg-turbo
|
||||||
|
- JuicyPixels-stbir
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
swift:
|
swift:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
trap "rm apps/multiplatform/local.properties || true; rm local.properties || true; rm /tmp/simplex.keychain || true" EXIT
|
trap "rm apps/multiplatform/local.properties 2> /dev/null || true; rm local.properties 2> /dev/null || true; rm /tmp/simplex.keychain" EXIT
|
||||||
echo "desktop.mac.signing.identity=Developer ID Application: SimpleX Chat Ltd (5NN7GUYB6T)" >> apps/multiplatform/local.properties
|
echo "desktop.mac.signing.identity=Developer ID Application: SimpleX Chat Ltd (5NN7GUYB6T)" >> apps/multiplatform/local.properties
|
||||||
echo "desktop.mac.signing.keychain=/tmp/simplex.keychain" >> apps/multiplatform/local.properties
|
echo "desktop.mac.signing.keychain=/tmp/simplex.keychain" >> apps/multiplatform/local.properties
|
||||||
echo "desktop.mac.notarization.apple_id=$APPLE_SIMPLEX_NOTARIZATION_APPLE_ID" >> apps/multiplatform/local.properties
|
echo "desktop.mac.notarization.apple_id=$APPLE_SIMPLEX_NOTARIZATION_APPLE_ID" >> apps/multiplatform/local.properties
|
||||||
@@ -10,6 +10,10 @@ echo "desktop.mac.notarization.password=$APPLE_SIMPLEX_NOTARIZATION_PASSWORD" >>
|
|||||||
echo "desktop.mac.notarization.team_id=5NN7GUYB6T" >> apps/multiplatform/local.properties
|
echo "desktop.mac.notarization.team_id=5NN7GUYB6T" >> apps/multiplatform/local.properties
|
||||||
echo "$APPLE_SIMPLEX_SIGNING_KEYCHAIN" | base64 --decode -o /tmp/simplex.keychain
|
echo "$APPLE_SIMPLEX_SIGNING_KEYCHAIN" | base64 --decode -o /tmp/simplex.keychain
|
||||||
|
|
||||||
|
security unlock-keychain -p "" /tmp/simplex.keychain
|
||||||
|
# Adding keychain to the list of keychains.
|
||||||
|
# Otherwise, it can find cert but exits while signing with "error: The specified item could not be found in the keychain."
|
||||||
|
security list-keychains -s `security list-keychains | xargs` /tmp/simplex.keychain
|
||||||
scripts/desktop/build-lib-mac.sh
|
scripts/desktop/build-lib-mac.sh
|
||||||
cd apps/multiplatform
|
cd apps/multiplatform
|
||||||
./gradlew packageDmg
|
./gradlew packageDmg
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
security create-keychain -p "" simplex.keychain
|
||||||
|
security set-keychain-settings -u simplex.keychain
|
||||||
|
security add-certificates -k simplex.keychain "Developer ID Application: SimpleX Chat Ltd (5NN7GUYB6T).cer"
|
||||||
|
security add-certificates -k simplex.keychain "Developer ID Certification Authority.cer"
|
||||||
|
# Private key with access from any app
|
||||||
|
security import "SimpleX Chat.p12" -P "" -k simplex.keychain -A
|
||||||
|
# Public key
|
||||||
|
security import "SimpleX Chat.pem" -k simplex.keychain
|
||||||
@@ -8,7 +8,7 @@ function readlink() {
|
|||||||
|
|
||||||
OS=linux
|
OS=linux
|
||||||
ARCH=${1:-`uname -a | rev | cut -d' ' -f2 | rev`}
|
ARCH=${1:-`uname -a | rev | cut -d' ' -f2 | rev`}
|
||||||
GHC_VERSION=8.10.7
|
GHC_VERSION=9.6.3
|
||||||
|
|
||||||
if [ "$ARCH" == "aarch64" ]; then
|
if [ "$ARCH" == "aarch64" ]; then
|
||||||
COMPOSE_ARCH=arm64
|
COMPOSE_ARCH=arm64
|
||||||
@@ -25,7 +25,7 @@ for elem in "${exports[@]}"; do count=$(grep -R "$elem$" libsimplex.dll.def | wc
|
|||||||
for elem in "${exports[@]}"; do count=$(grep -R "\"$elem\"" flake.nix | wc -l); if [ $count -ne 2 ]; then echo Wrong exports in flake.nix. Add \"$elem\" in two places of the file; exit 1; fi ; done
|
for elem in "${exports[@]}"; do count=$(grep -R "\"$elem\"" flake.nix | wc -l); if [ $count -ne 2 ]; then echo Wrong exports in flake.nix. Add \"$elem\" in two places of the file; exit 1; fi ; done
|
||||||
|
|
||||||
rm -rf $BUILD_DIR
|
rm -rf $BUILD_DIR
|
||||||
cabal build lib:simplex-chat --ghc-options='-optl-Wl,-rpath,$ORIGIN' --ghc-options="-optl-L$(ghc --print-libdir)/rts -optl-Wl,--as-needed,-lHSrts_thr-ghc$GHC_VERSION" --constraint 'simplexmq +client_library'
|
cabal build lib:simplex-chat --ghc-options='-optl-Wl,-rpath,$ORIGIN -flink-rts -threaded' --constraint 'simplexmq +client_library'
|
||||||
cd $BUILD_DIR/build
|
cd $BUILD_DIR/build
|
||||||
#patchelf --add-needed libHSrts_thr-ghc${GHC_VERSION}.so libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so
|
#patchelf --add-needed libHSrts_thr-ghc${GHC_VERSION}.so libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so
|
||||||
#patchelf --add-rpath '$ORIGIN' libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so
|
#patchelf --add-rpath '$ORIGIN' libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ set -e
|
|||||||
OS=mac
|
OS=mac
|
||||||
ARCH="${1:-`uname -a | rev | cut -d' ' -f1 | rev`}"
|
ARCH="${1:-`uname -a | rev | cut -d' ' -f1 | rev`}"
|
||||||
COMPOSE_ARCH=$ARCH
|
COMPOSE_ARCH=$ARCH
|
||||||
GHC_VERSION=8.10.7
|
GHC_VERSION=9.6.3
|
||||||
|
|
||||||
if [ "$ARCH" == "arm64" ]; then
|
if [ "$ARCH" == "arm64" ]; then
|
||||||
ARCH=aarch64
|
ARCH=aarch64
|
||||||
else
|
else
|
||||||
COMPOSE_ARCH=x64
|
COMPOSE_ARCH=x64
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LIB_EXT=dylib
|
LIB_EXT=dylib
|
||||||
LIB=libHSsimplex-chat-*-inplace-ghc*.$LIB_EXT
|
LIB=libHSsimplex-chat-*-inplace-ghc*.$LIB_EXT
|
||||||
GHC_LIBS_DIR=$(ghc --print-libdir)
|
GHC_LIBS_DIR=$(ghc --print-libdir)
|
||||||
@@ -23,13 +24,26 @@ for elem in "${exports[@]}"; do count=$(grep -R "$elem$" libsimplex.dll.def | wc
|
|||||||
for elem in "${exports[@]}"; do count=$(grep -R "\"$elem\"" flake.nix | wc -l); if [ $count -ne 2 ]; then echo Wrong exports in flake.nix. Add \"$elem\" in two places of the file; exit 1; fi ; done
|
for elem in "${exports[@]}"; do count=$(grep -R "\"$elem\"" flake.nix | wc -l); if [ $count -ne 2 ]; then echo Wrong exports in flake.nix. Add \"$elem\" in two places of the file; exit 1; fi ; done
|
||||||
|
|
||||||
rm -rf $BUILD_DIR
|
rm -rf $BUILD_DIR
|
||||||
cabal build lib:simplex-chat lib:simplex-chat --ghc-options="-optl-Wl,-rpath,@loader_path -optl-Wl,-L$GHC_LIBS_DIR/rts -optl-lHSrts_thr-ghc8.10.7 -optl-lffi" --constraint 'simplexmq +client_library'
|
cabal build lib:simplex-chat lib:simplex-chat --ghc-options="-optl-Wl,-rpath,@loader_path -optl-Wl,-L$GHC_LIBS_DIR/$ARCH-osx-ghc-$GHC_VERSION -optl-lHSrts_thr-ghc$GHC_VERSION -optl-lffi" --constraint 'simplexmq +client_library'
|
||||||
|
|
||||||
cd $BUILD_DIR/build
|
cd $BUILD_DIR/build
|
||||||
mkdir deps 2> /dev/null || true
|
mkdir deps 2> /dev/null || true
|
||||||
|
|
||||||
# It's not included by default for some reason. Compiled lib tries to find system one but it's not always available
|
# It's not included by default for some reason. Compiled lib tries to find system one but it's not always available
|
||||||
cp $GHC_LIBS_DIR/rts/libffi.dylib ./deps
|
#cp $GHC_LIBS_DIR/libffi.dylib ./deps
|
||||||
|
(
|
||||||
|
BUILD=$PWD
|
||||||
|
cp /tmp/libffi-3.4.4/*-apple-darwin*/.libs/libffi.dylib $BUILD/deps || \
|
||||||
|
( \
|
||||||
|
cd /tmp && \
|
||||||
|
curl --tlsv1.2 "https://gitlab.haskell.org/ghc/libffi-tarballs/-/raw/libffi-3.4.4/libffi-3.4.4.tar.gz?inline=false" -o libffi.tar.gz && \
|
||||||
|
tar -xzvf libffi.tar.gz && \
|
||||||
|
cd "libffi-3.4.4" && \
|
||||||
|
./configure && \
|
||||||
|
make && \
|
||||||
|
cp *-apple-darwin*/.libs/libffi.dylib $BUILD/deps \
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
DYLIBS=`otool -L $LIB | grep @rpath | tail -n +2 | cut -d' ' -f 1 | cut -d'/' -f2`
|
DYLIBS=`otool -L $LIB | grep @rpath | tail -n +2 | cut -d' ' -f 1 | cut -d'/' -f2`
|
||||||
RPATHS=`otool -l $LIB | grep "path "| cut -d' ' -f11`
|
RPATHS=`otool -l $LIB | grep "path "| cut -d' ' -f11`
|
||||||
@@ -70,6 +84,8 @@ function copy_deps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
copy_deps $LIB
|
copy_deps $LIB
|
||||||
|
# Special case
|
||||||
|
cp $(ghc --print-libdir)/$ARCH-osx-ghc-$GHC_VERSION/libHSghc-boot-th-$GHC_VERSION-ghc$GHC_VERSION.dylib deps
|
||||||
rm deps/`basename $LIB`
|
rm deps/`basename $LIB`
|
||||||
|
|
||||||
cd -
|
cd -
|
||||||
|
|||||||
@@ -0,0 +1,242 @@
|
|||||||
|
From 38be2c93acb6f459d24ed6c626981c35ccf44095 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sylvain Henry <sylvain@haskus.fr>
|
||||||
|
Date: Thu, 16 Feb 2023 15:40:45 +0100
|
||||||
|
Subject: [PATCH] Fix build on 32-bit architectures
|
||||||
|
|
||||||
|
---
|
||||||
|
Basement/Bits.hs | 4 ++++
|
||||||
|
Basement/From.hs | 24 -----------------------
|
||||||
|
Basement/Numerical/Additive.hs | 4 ++++
|
||||||
|
Basement/Numerical/Conversion.hs | 20 +++++++++++++++++++
|
||||||
|
Basement/PrimType.hs | 6 +++++-
|
||||||
|
Basement/Types/OffsetSize.hs | 22 +++++++++++++++++++--
|
||||||
|
6 files changed, 53 insertions(+), 27 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Basement/Bits.hs b/Basement/Bits.hs
|
||||||
|
index 7eeea0f5..24520ed7 100644
|
||||||
|
--- a/Basement/Bits.hs
|
||||||
|
+++ b/Basement/Bits.hs
|
||||||
|
@@ -54,8 +54,12 @@ import GHC.Int
|
||||||
|
import Basement.Compat.Primitive
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+import GHC.Exts
|
||||||
|
+#else
|
||||||
|
import GHC.IntWord64
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
-- | operation over finite bits
|
||||||
|
class FiniteBitsOps bits where
|
||||||
|
diff --git a/Basement/From.hs b/Basement/From.hs
|
||||||
|
index 7bbe141c..80014b3e 100644
|
||||||
|
--- a/Basement/From.hs
|
||||||
|
+++ b/Basement/From.hs
|
||||||
|
@@ -272,23 +272,11 @@ instance (NatWithinBound (CountOf ty) n, KnownNat n, PrimType ty)
|
||||||
|
tryFrom = BlockN.toBlockN . UArray.toBlock . BoxArray.mapToUnboxed id
|
||||||
|
|
||||||
|
instance (KnownNat n, NatWithinBound Word8 n) => From (Zn64 n) Word8 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . unZn64 where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . unZn64 where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance (KnownNat n, NatWithinBound Word16 n) => From (Zn64 n) Word16 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . unZn64 where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . unZn64 where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance (KnownNat n, NatWithinBound Word32 n) => From (Zn64 n) Word32 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . unZn64 where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . unZn64 where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance From (Zn64 n) Word64 where
|
||||||
|
from = unZn64
|
||||||
|
instance From (Zn64 n) Word128 where
|
||||||
|
@@ -297,23 +285,11 @@ instance From (Zn64 n) Word256 where
|
||||||
|
from = from . unZn64
|
||||||
|
|
||||||
|
instance (KnownNat n, NatWithinBound Word8 n) => From (Zn n) Word8 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance (KnownNat n, NatWithinBound Word16 n) => From (Zn n) Word16 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance (KnownNat n, NatWithinBound Word32 n) => From (Zn n) Word32 where
|
||||||
|
-#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# (GHC.Prim.word64ToWord# w)))
|
||||||
|
-#else
|
||||||
|
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# w))
|
||||||
|
-#endif
|
||||||
|
instance (KnownNat n, NatWithinBound Word64 n) => From (Zn n) Word64 where
|
||||||
|
from = naturalToWord64 . unZn
|
||||||
|
instance (KnownNat n, NatWithinBound Word128 n) => From (Zn n) Word128 where
|
||||||
|
diff --git a/Basement/Numerical/Additive.hs b/Basement/Numerical/Additive.hs
|
||||||
|
index d0dfb973..8ab65aa0 100644
|
||||||
|
--- a/Basement/Numerical/Additive.hs
|
||||||
|
+++ b/Basement/Numerical/Additive.hs
|
||||||
|
@@ -30,8 +30,12 @@ import qualified Basement.Types.Word128 as Word128
|
||||||
|
import qualified Basement.Types.Word256 as Word256
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+import GHC.Exts
|
||||||
|
+#else
|
||||||
|
import GHC.IntWord64
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
-- | Represent class of things that can be added together,
|
||||||
|
-- contains a neutral element and is commutative.
|
||||||
|
diff --git a/Basement/Numerical/Conversion.hs b/Basement/Numerical/Conversion.hs
|
||||||
|
index db502c07..fddc8232 100644
|
||||||
|
--- a/Basement/Numerical/Conversion.hs
|
||||||
|
+++ b/Basement/Numerical/Conversion.hs
|
||||||
|
@@ -26,8 +26,12 @@ import GHC.Word
|
||||||
|
import Basement.Compat.Primitive
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+import GHC.Exts
|
||||||
|
+#else
|
||||||
|
import GHC.IntWord64
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
intToInt64 :: Int -> Int64
|
||||||
|
#if WORD_SIZE_IN_BITS == 64
|
||||||
|
@@ -96,11 +100,22 @@ int64ToWord64 (I64# i) = W64# (int64ToWord64# i)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS == 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+word64ToWord# :: Word64# -> Word#
|
||||||
|
+word64ToWord# i = word64ToWord# i
|
||||||
|
+#else
|
||||||
|
word64ToWord# :: Word# -> Word#
|
||||||
|
word64ToWord# i = i
|
||||||
|
+#endif
|
||||||
|
{-# INLINE word64ToWord# #-}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+word64ToWord32# :: Word64# -> Word32#
|
||||||
|
+word64ToWord32# i = wordToWord32# (word64ToWord# i)
|
||||||
|
+{-# INLINE word64ToWord32# #-}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
-- | 2 Word32s
|
||||||
|
data Word32x2 = Word32x2 {-# UNPACK #-} !Word32
|
||||||
|
{-# UNPACK #-} !Word32
|
||||||
|
@@ -113,9 +128,14 @@ word64ToWord32s (W64# w64) = Word32x2 (W32# (wordToWord32# (uncheckedShiftRL# (G
|
||||||
|
word64ToWord32s (W64# w64) = Word32x2 (W32# (wordToWord32# (uncheckedShiftRL# w64 32#))) (W32# (wordToWord32# w64))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+word64ToWord32s :: Word64 -> Word32x2
|
||||||
|
+word64ToWord32s (W64# w64) = Word32x2 (W32# (word64ToWord32# (uncheckedShiftRL64# w64 32#))) (W32# (word64ToWord32# w64))
|
||||||
|
+#else
|
||||||
|
word64ToWord32s :: Word64 -> Word32x2
|
||||||
|
word64ToWord32s (W64# w64) = Word32x2 (W32# (word64ToWord# (uncheckedShiftRL64# w64 32#))) (W32# (word64ToWord# w64))
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
wordToChar :: Word -> Char
|
||||||
|
wordToChar (W# word) = C# (chr# (word2Int# word))
|
||||||
|
diff --git a/Basement/PrimType.hs b/Basement/PrimType.hs
|
||||||
|
index f8ca2926..a888ec91 100644
|
||||||
|
--- a/Basement/PrimType.hs
|
||||||
|
+++ b/Basement/PrimType.hs
|
||||||
|
@@ -54,7 +54,11 @@ import Basement.Nat
|
||||||
|
import qualified Prelude (quot)
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
-import GHC.IntWord64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+import GHC.Exts
|
||||||
|
+#else
|
||||||
|
+import GHC.IntWord64
|
||||||
|
+#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FOUNDATION_BOUNDS_CHECK
|
||||||
|
diff --git a/Basement/Types/OffsetSize.hs b/Basement/Types/OffsetSize.hs
|
||||||
|
index cd944927..1ea80dad 100644
|
||||||
|
--- a/Basement/Types/OffsetSize.hs
|
||||||
|
+++ b/Basement/Types/OffsetSize.hs
|
||||||
|
@@ -70,8 +70,12 @@ import Data.List (foldl')
|
||||||
|
import qualified Prelude
|
||||||
|
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+import GHC.Exts
|
||||||
|
+#else
|
||||||
|
import GHC.IntWord64
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
-- | File size in bytes
|
||||||
|
newtype FileSize = FileSize Word64
|
||||||
|
@@ -225,20 +229,26 @@ countOfRoundUp alignment (CountOf n) = CountOf ((n + (alignment-1)) .&. compleme
|
||||||
|
|
||||||
|
csizeOfSize :: CountOf Word8 -> CSize
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+csizeOfSize (CountOf (I# sz)) = CSize (W32# (wordToWord32# (int2Word# sz)))
|
||||||
|
+#else
|
||||||
|
csizeOfSize (CountOf (I# sz)) = CSize (W32# (int2Word# sz))
|
||||||
|
+#endif
|
||||||
|
#else
|
||||||
|
#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
csizeOfSize (CountOf (I# sz)) = CSize (W64# (wordToWord64# (int2Word# sz)))
|
||||||
|
-
|
||||||
|
#else
|
||||||
|
csizeOfSize (CountOf (I# sz)) = CSize (W64# (int2Word# sz))
|
||||||
|
-
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
csizeOfOffset :: Offset8 -> CSize
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+csizeOfOffset (Offset (I# sz)) = CSize (W32# (wordToWord32# (int2Word# sz)))
|
||||||
|
+#else
|
||||||
|
csizeOfOffset (Offset (I# sz)) = CSize (W32# (int2Word# sz))
|
||||||
|
+#endif
|
||||||
|
#else
|
||||||
|
#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
csizeOfOffset (Offset (I# sz)) = CSize (W64# (wordToWord64# (int2Word# sz)))
|
||||||
|
@@ -250,7 +260,11 @@ csizeOfOffset (Offset (I# sz)) = CSize (W64# (int2Word# sz))
|
||||||
|
sizeOfCSSize :: CSsize -> CountOf Word8
|
||||||
|
sizeOfCSSize (CSsize (-1)) = error "invalid size: CSSize is -1"
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+sizeOfCSSize (CSsize (I32# sz)) = CountOf (I# (int32ToInt# sz))
|
||||||
|
+#else
|
||||||
|
sizeOfCSSize (CSsize (I32# sz)) = CountOf (I# sz)
|
||||||
|
+#endif
|
||||||
|
#else
|
||||||
|
#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
sizeOfCSSize (CSsize (I64# sz)) = CountOf (I# (int64ToInt# sz))
|
||||||
|
@@ -261,7 +275,11 @@ sizeOfCSSize (CSsize (I64# sz)) = CountOf (I# sz)
|
||||||
|
|
||||||
|
sizeOfCSize :: CSize -> CountOf Word8
|
||||||
|
#if WORD_SIZE_IN_BITS < 64
|
||||||
|
+#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
+sizeOfCSize (CSize (W32# sz)) = CountOf (I# (word2Int# (word32ToWord# sz)))
|
||||||
|
+#else
|
||||||
|
sizeOfCSize (CSize (W32# sz)) = CountOf (I# (word2Int# sz))
|
||||||
|
+#endif
|
||||||
|
#else
|
||||||
|
#if __GLASGOW_HASKELL__ >= 904
|
||||||
|
sizeOfCSize (CSize (W64# sz)) = CountOf (I# (word2Int# (word64ToWord# sz)))
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff --git a/direct-sqlcipher.cabal b/direct-sqlcipher.cabal
|
||||||
|
index 728ba3e..c63745e 100644
|
||||||
|
--- a/direct-sqlcipher.cabal
|
||||||
|
+++ b/direct-sqlcipher.cabal
|
||||||
|
@@ -84,6 +84,8 @@ library
|
||||||
|
cc-options: -DSQLITE_TEMP_STORE=2
|
||||||
|
-DSQLITE_HAS_CODEC
|
||||||
|
|
||||||
|
+ extra-libraries: ws2_32
|
||||||
|
+
|
||||||
|
if !os(windows) && !os(android)
|
||||||
|
extra-libraries: pthread
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
From 2738929ce15b4c8704bbbac24a08539b5d4bf30e Mon Sep 17 00:00:00 2001
|
||||||
|
From: sternenseemann <sternenseemann@systemli.org>
|
||||||
|
Date: Mon, 14 Aug 2023 10:51:30 +0200
|
||||||
|
Subject: [PATCH] Data.Memory.Internal.CompatPrim64: fix 32 bit with GHC >= 9.4
|
||||||
|
|
||||||
|
Since 9.4, GHC.Prim exports Word64# operations like timesWord64# even on
|
||||||
|
i686 whereas GHC.IntWord64 no longer exists. Therefore, we can just use
|
||||||
|
the ready made solution.
|
||||||
|
|
||||||
|
Closes #98, as it should be the better solution.
|
||||||
|
---
|
||||||
|
Data/Memory/Internal/CompatPrim64.hs | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/Data/Memory/Internal/CompatPrim64.hs b/Data/Memory/Internal/CompatPrim64.hs
|
||||||
|
index b9eef8a..a134c88 100644
|
||||||
|
--- a/Data/Memory/Internal/CompatPrim64.hs
|
||||||
|
+++ b/Data/Memory/Internal/CompatPrim64.hs
|
||||||
|
@@ -150,6 +150,7 @@ w64# :: Word# -> Word# -> Word# -> Word64#
|
||||||
|
w64# w _ _ = w
|
||||||
|
|
||||||
|
#elif WORD_SIZE_IN_BITS == 32
|
||||||
|
+#if __GLASGOW_HASKELL__ < 904
|
||||||
|
import GHC.IntWord64
|
||||||
|
import GHC.Prim (Word#)
|
||||||
|
|
||||||
|
@@ -158,6 +159,9 @@ timesWord64# a b =
|
||||||
|
let !ai = word64ToInt64# a
|
||||||
|
!bi = word64ToInt64# b
|
||||||
|
in int64ToWord64# (timesInt64# ai bi)
|
||||||
|
+#else
|
||||||
|
+import GHC.Prim
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
w64# :: Word# -> Word# -> Word# -> Word64#
|
||||||
|
w64# _ hw lw =
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"https://github.com/simplex-chat/simplexmq.git"."79e9447b73cc315ce35042b0a5f210c07ea39b07" = "16z7z5a3f7gw0h188manykp008d1bqpydlrj7h497mgyjmp4cy9m";
|
"https://github.com/simplex-chat/simplexmq.git"."0a827307d666de819d5cef17f70a78be5cd0e410" = "09z0y6w1c51szd9r90fl259inn76yahfbb164mawd34sr41ccp7g";
|
||||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||||
@@ -9,4 +9,5 @@
|
|||||||
"https://github.com/simplex-chat/zip.git"."bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc" = "1csqfjhvc8wb5h4kxxndmb6iw7b4ib9ff2n81hrizsmnf45a6gg0";
|
"https://github.com/simplex-chat/zip.git"."bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc" = "1csqfjhvc8wb5h4kxxndmb6iw7b4ib9ff2n81hrizsmnf45a6gg0";
|
||||||
"https://github.com/yesodweb/wai.git"."ec5e017d896a78e787a5acea62b37a4e677dec2e" = "1ckcpmpjfy9jiqrb52q20lj7ln4hmq9v2jk6kpkf3m68c1m9c2bx";
|
"https://github.com/yesodweb/wai.git"."ec5e017d896a78e787a5acea62b37a4e677dec2e" = "1ckcpmpjfy9jiqrb52q20lj7ln4hmq9v2jk6kpkf3m68c1m9c2bx";
|
||||||
"https://github.com/simplex-chat/wai.git"."2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0" = "199g4rjdf1zp1fcw8nqdsyr1h36hmg424qqx03071jk7j00z7ay4";
|
"https://github.com/simplex-chat/wai.git"."2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0" = "199g4rjdf1zp1fcw8nqdsyr1h36hmg424qqx03071jk7j00z7ay4";
|
||||||
|
"https://gitlab.com/dpwiz/hs-jpeg-turbo"."d2844e00e7834124e27171cde21cf280d6772aa8" = "1gbvpkx7g2r62bfgpmf8ljdvpccnskdnhqzblm515cb70pyrfq07";
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-7
@@ -35,6 +35,7 @@ library
|
|||||||
Simplex.Chat.Core
|
Simplex.Chat.Core
|
||||||
Simplex.Chat.Files
|
Simplex.Chat.Files
|
||||||
Simplex.Chat.Help
|
Simplex.Chat.Help
|
||||||
|
Simplex.Chat.Image
|
||||||
Simplex.Chat.Markdown
|
Simplex.Chat.Markdown
|
||||||
Simplex.Chat.Messages
|
Simplex.Chat.Messages
|
||||||
Simplex.Chat.Messages.Batch
|
Simplex.Chat.Messages.Batch
|
||||||
@@ -205,7 +206,10 @@ library
|
|||||||
StrictData
|
StrictData
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -270,7 +274,10 @@ executable simplex-bot
|
|||||||
StrictData
|
StrictData
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -336,7 +343,10 @@ executable simplex-bot-advanced
|
|||||||
StrictData
|
StrictData
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -405,7 +415,10 @@ executable simplex-broadcast-bot
|
|||||||
Paths_simplex_chat
|
Paths_simplex_chat
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -472,7 +485,10 @@ executable simplex-chat
|
|||||||
StrictData
|
StrictData
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -545,7 +561,10 @@ executable simplex-directory-service
|
|||||||
Paths_simplex_chat
|
Paths_simplex_chat
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ==2.2.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
, attoparsec ==0.14.*
|
, attoparsec ==0.14.*
|
||||||
@@ -618,6 +637,7 @@ test-suite simplex-chat-test
|
|||||||
ChatTests.Profiles
|
ChatTests.Profiles
|
||||||
ChatTests.Utils
|
ChatTests.Utils
|
||||||
JSONTests
|
JSONTests
|
||||||
|
LinkPreviewTests
|
||||||
MarkdownTests
|
MarkdownTests
|
||||||
MessageBatching
|
MessageBatching
|
||||||
MobileTests
|
MobileTests
|
||||||
@@ -645,7 +665,10 @@ test-suite simplex-chat-test
|
|||||||
StrictData
|
StrictData
|
||||||
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
ghc-options: -O2 -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-unused-packages -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=missing-methods -Werror=incomplete-uni-patterns -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -threaded
|
||||||
build-depends:
|
build-depends:
|
||||||
QuickCheck ==2.14.*
|
JuicyPixels
|
||||||
|
, JuicyPixels-jpeg-turbo
|
||||||
|
, JuicyPixels-stbir
|
||||||
|
, QuickCheck ==2.14.*
|
||||||
, aeson ==2.2.*
|
, aeson ==2.2.*
|
||||||
, ansi-terminal >=0.10 && <0.12
|
, ansi-terminal >=0.10 && <0.12
|
||||||
, async ==2.2.*
|
, async ==2.2.*
|
||||||
|
|||||||
+1
-2
@@ -92,9 +92,8 @@ import Simplex.Chat.Types.Preferences
|
|||||||
import Simplex.Chat.Types.Shared
|
import Simplex.Chat.Types.Shared
|
||||||
import Simplex.Chat.Util (encryptFile, liftIOEither, shuffle)
|
import Simplex.Chat.Util (encryptFile, liftIOEither, shuffle)
|
||||||
import qualified Simplex.Chat.Util as U
|
import qualified Simplex.Chat.Util as U
|
||||||
import Simplex.FileTransfer.Client.Main (maxFileSize, maxFileSizeHard)
|
|
||||||
import Simplex.FileTransfer.Client.Presets (defaultXFTPServers)
|
import Simplex.FileTransfer.Client.Presets (defaultXFTPServers)
|
||||||
import Simplex.FileTransfer.Description (FileDescriptionURI (..), ValidFileDescription)
|
import Simplex.FileTransfer.Description (FileDescriptionURI (..), ValidFileDescription, maxFileSize, maxFileSizeHard)
|
||||||
import qualified Simplex.FileTransfer.Description as FD
|
import qualified Simplex.FileTransfer.Description as FD
|
||||||
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
|
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
|
||||||
import qualified Simplex.FileTransfer.Transport as XFTP
|
import qualified Simplex.FileTransfer.Transport as XFTP
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
|
{-# LANGUAGE KindSignatures #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE RankNTypes #-}
|
||||||
|
{-# LANGUAGE TupleSections #-}
|
||||||
|
{-# LANGUAGE TypeSynonymInstances #-}
|
||||||
|
|
||||||
|
module Simplex.Chat.Image where
|
||||||
|
|
||||||
|
import qualified Codec.Picture as Picture
|
||||||
|
import qualified Codec.Picture.JPEGTurbo as JT
|
||||||
|
import Codec.Picture.Metadata (Metadatas)
|
||||||
|
import Codec.Picture.Png (encodePng)
|
||||||
|
import qualified Codec.Picture.STBIR as STBIR
|
||||||
|
import Codec.Picture.Types (dropAlphaLayer, pixelFoldMap)
|
||||||
|
import Control.Monad.Except (ExceptT (..), runExceptT, throwError)
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString.Base64.Lazy as LB64
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||||
|
import Data.Int (Int64)
|
||||||
|
import Data.Monoid (All (..))
|
||||||
|
import System.IO.Unsafe (unsafePerformIO)
|
||||||
|
|
||||||
|
resizeImageToSize :: Bool -> Int -> Int64 -> ResizeableImage -> LB.ByteString
|
||||||
|
resizeImageToSize toURI minJpegQuality maxSize (ResizeableImage fmt img encoder) = either resizePNG resizeJPG encoder
|
||||||
|
where
|
||||||
|
halveAndRetry = resizeImageToSize toURI minJpegQuality maxSize (ResizeableImage fmt imgHalved encoder)
|
||||||
|
imgHalved = downscale img 2.0
|
||||||
|
resizePNG enc
|
||||||
|
| LB.length encoded <= maxSize = encoded
|
||||||
|
| LB.length (encode imgHalved) > maxSize = halveAndRetry
|
||||||
|
| otherwise = fitScale 1.0 2.0
|
||||||
|
where
|
||||||
|
encode
|
||||||
|
| toURI = toDataUri "png" . enc
|
||||||
|
| otherwise = enc
|
||||||
|
encoded = encode img
|
||||||
|
fitScale l u
|
||||||
|
| u - l < 1 / 64 = encode $ downscale img u -- prefer lower resolution
|
||||||
|
| otherwise =
|
||||||
|
case compare maxSize (LB.length result) of
|
||||||
|
LT -> fitScale m u -- over budget, scale harder
|
||||||
|
EQ -> result
|
||||||
|
GT -> fitScale l m -- keep more pixels
|
||||||
|
where
|
||||||
|
m = (l + u) / 2
|
||||||
|
result = encode $ downscale img m
|
||||||
|
resizeJPG enc
|
||||||
|
| minSize > maxSize = halveAndRetry
|
||||||
|
| otherwise = fitQuality minJpegQuality 95
|
||||||
|
where
|
||||||
|
encode q
|
||||||
|
| toURI = toDataUri "jpg" $ enc q img -- the correct mime type is "jpeg", but only "jpg" is supported by older clients
|
||||||
|
| otherwise = enc q img
|
||||||
|
minSize = LB.length $ encode minJpegQuality
|
||||||
|
fitQuality l u
|
||||||
|
| u - l <= 1 = encode l -- prefer higher compression
|
||||||
|
| otherwise =
|
||||||
|
case compare (LB.length result) maxSize of
|
||||||
|
LT -> fitQuality m u -- keep more data
|
||||||
|
EQ -> result
|
||||||
|
GT -> fitQuality l m -- over budget, reduce quality
|
||||||
|
where
|
||||||
|
m = (l + u) `div` 2
|
||||||
|
result = encode m
|
||||||
|
|
||||||
|
downscale :: STBIR.STBIRPixel pixel => Picture.Image pixel -> Float -> Picture.Image pixel
|
||||||
|
downscale img scale = STBIR.resize STBIR.defaultOptions (scaled Picture.imageWidth) (scaled Picture.imageHeight) img
|
||||||
|
where
|
||||||
|
scaled f = round $ fromIntegral (f img) / min 2.0 (max 0.5 scale)
|
||||||
|
|
||||||
|
toDataUri :: LB.ByteString -> LB.ByteString -> LB.ByteString
|
||||||
|
toDataUri fmt body = "data:image/" <> fmt <> ";base64," <> LB64.encode body
|
||||||
|
|
||||||
|
decodeResizeable :: ByteString -> Either String (ResizeableImage, Metadatas)
|
||||||
|
decodeResizeable source = do
|
||||||
|
(input, metadata) <- Picture.decodeImageWithMetadata source
|
||||||
|
maybe (Left "unsupported image format") (pure . (,metadata)) $ resizeableImage (tryDropOpacity input)
|
||||||
|
|
||||||
|
readResizeable :: FilePath -> IO (Either String (ResizeableImage, Metadatas))
|
||||||
|
readResizeable inputPath = runExceptT $ do
|
||||||
|
(input, metadata) <- ExceptT $ Picture.readImageWithMetadata inputPath -- will use mmap instead of reading the whole file
|
||||||
|
maybe (throwError "unsupported image format") (pure . (,metadata)) $ resizeableImage (tryDropOpacity input)
|
||||||
|
|
||||||
|
tryDropOpacity :: Picture.DynamicImage -> Picture.DynamicImage
|
||||||
|
tryDropOpacity dyn = case dyn of
|
||||||
|
Picture.ImageRGBA16 img | opaque img -> Picture.ImageRGB16 $ dropAlphaLayer img
|
||||||
|
Picture.ImageRGBA8 img | opaque img -> Picture.ImageRGB8 $ dropAlphaLayer img
|
||||||
|
Picture.ImageYA16 img | opaque img -> Picture.ImageY16 $ dropAlphaLayer img
|
||||||
|
Picture.ImageYA8 img | opaque img -> Picture.ImageY8 $ dropAlphaLayer img
|
||||||
|
_ -> dyn
|
||||||
|
where
|
||||||
|
opaque :: (Picture.Pixel a, Eq (Picture.PixelBaseComponent a), Bounded (Picture.PixelBaseComponent a)) => Picture.Image a -> Bool
|
||||||
|
opaque = getAll . pixelFoldMap (All . \pix -> Picture.pixelOpacity pix == maxBound)
|
||||||
|
|
||||||
|
data ResizeableImage where
|
||||||
|
ResizeableImage ::
|
||||||
|
STBIR.STBIRPixel a =>
|
||||||
|
-- | format label
|
||||||
|
String ->
|
||||||
|
-- | current image data
|
||||||
|
Picture.Image a ->
|
||||||
|
ImageEncoder a ->
|
||||||
|
ResizeableImage
|
||||||
|
|
||||||
|
type ImageEncoder a = Either (PNGEncoder a) (JPGEncoder a)
|
||||||
|
type PNGEncoder a = Picture.Image a -> LB.ByteString
|
||||||
|
type JPGEncoder a = Int -> Picture.Image a -> LB.ByteString
|
||||||
|
|
||||||
|
resizeableImage :: Picture.DynamicImage -> Maybe ResizeableImage
|
||||||
|
resizeableImage dyn = case dyn of
|
||||||
|
Picture.ImageY8 img -> Just $ ResizeableImage "Y8" img $ Right $ \q -> LB.fromStrict . unsafePerformIO . JT.encodeRGB q . Picture.convertRGB8 . Picture.ImageY8 -- TODO: directly
|
||||||
|
Picture.ImageY16 img -> Just $ ResizeableImage "Y16" img $ Left encodePng
|
||||||
|
Picture.ImageY32 _ -> Nothing
|
||||||
|
Picture.ImageYF _ -> Nothing
|
||||||
|
Picture.ImageYA8 img -> Just $ ResizeableImage "YA8" img $ Left encodePng
|
||||||
|
Picture.ImageYA16 img -> Just $ ResizeableImage "YA16" img $ Left encodePng
|
||||||
|
Picture.ImageRGB8 img -> Just $ ResizeableImage "RGB8" img $ Right $ \q -> LB.fromStrict . unsafePerformIO . JT.encodeRGB q
|
||||||
|
Picture.ImageRGB16 img -> Just $ ResizeableImage "RGB16" img $ Left encodePng
|
||||||
|
Picture.ImageRGBF _ -> Nothing
|
||||||
|
Picture.ImageRGBA8 img -> Just $ ResizeableImage "RGBA8" img $ Left encodePng
|
||||||
|
Picture.ImageRGBA16 img -> Just $ ResizeableImage "RGBA16" img $ Left encodePng
|
||||||
|
Picture.ImageYCbCr8 img -> Just $ ResizeableImage "YCbCr8" img $ Right $ \q -> LB.fromStrict . unsafePerformIO . JT.encodeRGB q . Picture.convertRGB8 . Picture.ImageYCbCr8 -- TODO: JT.encodeYUV
|
||||||
|
Picture.ImageCMYK8 img -> Just $ ResizeableImage "CMYK8" img $ Right $ \q -> LB.fromStrict . unsafePerformIO . JT.encodeRGB q . Picture.convertRGB8 . Picture.ImageCMYK8
|
||||||
|
Picture.ImageCMYK16 _ -> Nothing
|
||||||
@@ -21,6 +21,7 @@ import qualified Data.ByteString.Base64.URL as U
|
|||||||
import Data.ByteString.Char8 (ByteString)
|
import Data.ByteString.Char8 (ByteString)
|
||||||
import qualified Data.ByteString.Char8 as B
|
import qualified Data.ByteString.Char8 as B
|
||||||
import qualified Data.ByteString.Lazy.Char8 as LB
|
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||||
|
import Data.Either (fromRight)
|
||||||
import Data.Functor (($>))
|
import Data.Functor (($>))
|
||||||
import Data.List (find)
|
import Data.List (find)
|
||||||
import qualified Data.List.NonEmpty as L
|
import qualified Data.List.NonEmpty as L
|
||||||
@@ -29,13 +30,14 @@ import Data.Word (Word8)
|
|||||||
import Database.SQLite.Simple (SQLError (..))
|
import Database.SQLite.Simple (SQLError (..))
|
||||||
import qualified Database.SQLite.Simple as DB
|
import qualified Database.SQLite.Simple as DB
|
||||||
import Foreign.C.String
|
import Foreign.C.String
|
||||||
import Foreign.C.Types (CInt (..))
|
import Foreign.C.Types (CBool (..), CInt (..), CLong (..))
|
||||||
import Foreign.Ptr
|
import Foreign.Ptr
|
||||||
import Foreign.StablePtr
|
import Foreign.StablePtr
|
||||||
import Foreign.Storable (poke)
|
import Foreign.Storable (poke)
|
||||||
import GHC.IO.Encoding (setFileSystemEncoding, setForeignEncoding, setLocaleEncoding)
|
import GHC.IO.Encoding (setFileSystemEncoding, setForeignEncoding, setLocaleEncoding)
|
||||||
import Simplex.Chat
|
import Simplex.Chat
|
||||||
import Simplex.Chat.Controller
|
import Simplex.Chat.Controller
|
||||||
|
import Simplex.Chat.Image (readResizeable, resizeImageToSize)
|
||||||
import Simplex.Chat.Markdown (ParsedMarkdown (..), parseMaybeMarkdownList)
|
import Simplex.Chat.Markdown (ParsedMarkdown (..), parseMaybeMarkdownList)
|
||||||
import Simplex.Chat.Mobile.File
|
import Simplex.Chat.Mobile.File
|
||||||
import Simplex.Chat.Mobile.Shared
|
import Simplex.Chat.Mobile.Shared
|
||||||
@@ -45,6 +47,7 @@ import Simplex.Chat.Remote.Types
|
|||||||
import Simplex.Chat.Store
|
import Simplex.Chat.Store
|
||||||
import Simplex.Chat.Store.Profiles
|
import Simplex.Chat.Store.Profiles
|
||||||
import Simplex.Chat.Types
|
import Simplex.Chat.Types
|
||||||
|
import Simplex.Chat.Util (liftIOEither)
|
||||||
import Simplex.Messaging.Agent.Client (agentClientStore)
|
import Simplex.Messaging.Agent.Client (agentClientStore)
|
||||||
import Simplex.Messaging.Agent.Env.SQLite (createAgentStore)
|
import Simplex.Messaging.Agent.Env.SQLite (createAgentStore)
|
||||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, closeSQLiteStore, reopenSQLiteStore)
|
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, closeSQLiteStore, reopenSQLiteStore)
|
||||||
@@ -102,12 +105,16 @@ foreign export ccall "chat_decrypt_media" cChatDecryptMedia :: CString -> Ptr Wo
|
|||||||
|
|
||||||
foreign export ccall "chat_write_file" cChatWriteFile :: StablePtr ChatController -> CString -> Ptr Word8 -> CInt -> IO CJSONString
|
foreign export ccall "chat_write_file" cChatWriteFile :: StablePtr ChatController -> CString -> Ptr Word8 -> CInt -> IO CJSONString
|
||||||
|
|
||||||
|
foreign export ccall "chat_write_image" cChatWriteImage :: StablePtr ChatController -> CLong -> CString -> Ptr Word8 -> CInt -> CBool -> IO CJSONString
|
||||||
|
|
||||||
foreign export ccall "chat_read_file" cChatReadFile :: CString -> CString -> CString -> IO (Ptr Word8)
|
foreign export ccall "chat_read_file" cChatReadFile :: CString -> CString -> CString -> IO (Ptr Word8)
|
||||||
|
|
||||||
foreign export ccall "chat_encrypt_file" cChatEncryptFile :: StablePtr ChatController -> CString -> CString -> IO CJSONString
|
foreign export ccall "chat_encrypt_file" cChatEncryptFile :: StablePtr ChatController -> CString -> CString -> IO CJSONString
|
||||||
|
|
||||||
foreign export ccall "chat_decrypt_file" cChatDecryptFile :: CString -> CString -> CString -> CString -> IO CString
|
foreign export ccall "chat_decrypt_file" cChatDecryptFile :: CString -> CString -> CString -> CString -> IO CString
|
||||||
|
|
||||||
|
foreign export ccall "chat_resize_image_to_str_size" cChatResizeImageToStrSize :: CString -> CLong -> IO CString
|
||||||
|
|
||||||
-- | check / migrate database and initialize chat controller on success
|
-- | check / migrate database and initialize chat controller on success
|
||||||
cChatMigrateInit :: CString -> CString -> CString -> Ptr (StablePtr ChatController) -> IO CJSONString
|
cChatMigrateInit :: CString -> CString -> CString -> Ptr (StablePtr ChatController) -> IO CJSONString
|
||||||
cChatMigrateInit fp key conf = cChatMigrateInitKey fp key 0 conf 0
|
cChatMigrateInit fp key conf = cChatMigrateInitKey fp key 0 conf 0
|
||||||
@@ -182,6 +189,37 @@ cChatValidName cName = newCString . mkValidName =<< peekCString cName
|
|||||||
cChatJsonLength :: CString -> IO CInt
|
cChatJsonLength :: CString -> IO CInt
|
||||||
cChatJsonLength s = fromIntegral . subtract 2 . LB.length . J.encode . safeDecodeUtf8 <$> B.packCString s
|
cChatJsonLength s = fromIntegral . subtract 2 . LB.length . J.encode . safeDecodeUtf8 <$> B.packCString s
|
||||||
|
|
||||||
|
-- -- | Resize image at path to match specified dimensions preserving aspect ratio
|
||||||
|
-- cChatResizeImageToFit :: CString -> CInt -> CInt -> IO CString
|
||||||
|
-- cChatResizeImageToFit path maxWidth maxHeight = error "todo"
|
||||||
|
|
||||||
|
-- -- | Resize image at path to match specified dimensions, cropping the extra pixels
|
||||||
|
-- cChatResizeImageCrop :: CString -> CInt -> CInt -> IO CString
|
||||||
|
-- cChatResizeImageCrop path width height = error "todo" -- аватарки
|
||||||
|
|
||||||
|
-- -- | Downscale image at path until it fits into specified size
|
||||||
|
-- cChatResizeImageToDataSize :: CString -> CInt -> IO CString
|
||||||
|
-- cChatResizeImageToDataSize path maxSize = error "todo"
|
||||||
|
|
||||||
|
-- | Downscale image at path until its data-uri encoding fits into specified size.
|
||||||
|
-- Returns data-uri/base64 encoded image as 0-terminated string.
|
||||||
|
-- Empty result string means operation failure.
|
||||||
|
-- The caller must free the result ptr.
|
||||||
|
cChatResizeImageToStrSize :: CString -> CLong -> IO CString
|
||||||
|
cChatResizeImageToStrSize fp' maxSize = do
|
||||||
|
fp <- peekCString fp'
|
||||||
|
res <- runExceptT $ do
|
||||||
|
(ri, _) <- liftIOEither $ readResizeable fp
|
||||||
|
let resized = resizeImageToSize True previewMinQuality (fromIntegral maxSize) ri
|
||||||
|
if LB.length resized > fromIntegral maxSize then throwError "unable to fit" else pure resized
|
||||||
|
newCStringFromLazyBS $ fromRight "" res
|
||||||
|
where
|
||||||
|
previewMinQuality = 20
|
||||||
|
|
||||||
|
-- -- | Strip EXIF etc metadata from image, inlplace
|
||||||
|
-- cChatStripImageMetadata :: CString -> IO CBool
|
||||||
|
-- cChatStripImageMetadata path = error "todo"
|
||||||
|
|
||||||
mobileChatOpts :: String -> ChatOpts
|
mobileChatOpts :: String -> ChatOpts
|
||||||
mobileChatOpts dbFilePrefix =
|
mobileChatOpts dbFilePrefix =
|
||||||
ChatOpts
|
ChatOpts
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
module Simplex.Chat.Mobile.File
|
module Simplex.Chat.Mobile.File
|
||||||
( cChatWriteFile,
|
( cChatWriteFile,
|
||||||
|
cChatWriteImage,
|
||||||
cChatReadFile,
|
cChatReadFile,
|
||||||
cChatEncryptFile,
|
cChatEncryptFile,
|
||||||
cChatDecryptFile,
|
cChatDecryptFile,
|
||||||
@@ -35,6 +36,8 @@ import Foreign.Ptr
|
|||||||
import Foreign.StablePtr
|
import Foreign.StablePtr
|
||||||
import Foreign.Storable (poke, pokeByteOff)
|
import Foreign.Storable (poke, pokeByteOff)
|
||||||
import Simplex.Chat.Controller (ChatController (..))
|
import Simplex.Chat.Controller (ChatController (..))
|
||||||
|
import Simplex.Chat.Image (resizeImageToSize)
|
||||||
|
import qualified Simplex.Chat.Image as Picture
|
||||||
import Simplex.Chat.Mobile.Shared
|
import Simplex.Chat.Mobile.Shared
|
||||||
import Simplex.Chat.Util (chunkSize, encryptFile)
|
import Simplex.Chat.Util (chunkSize, encryptFile)
|
||||||
import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..), CryptoFileHandle, FTCryptoError (..))
|
import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..), CryptoFileHandle, FTCryptoError (..))
|
||||||
@@ -45,7 +48,7 @@ import Simplex.Messaging.Util (catchAll)
|
|||||||
import UnliftIO (Handle, IOMode (..), atomically, withFile)
|
import UnliftIO (Handle, IOMode (..), atomically, withFile)
|
||||||
|
|
||||||
data WriteFileResult
|
data WriteFileResult
|
||||||
= WFResult {cryptoArgs :: CryptoFileArgs}
|
= WFResult {cryptoArgs :: Maybe CryptoFileArgs}
|
||||||
| WFError {writeError :: String}
|
| WFError {writeError :: String}
|
||||||
|
|
||||||
$(JQ.deriveToJSON (sumTypeJSON $ dropPrefix "WF") ''WriteFileResult)
|
$(JQ.deriveToJSON (sumTypeJSON $ dropPrefix "WF") ''WriteFileResult)
|
||||||
@@ -61,10 +64,32 @@ cChatWriteFile cc cPath ptr len = do
|
|||||||
chatWriteFile :: ChatController -> FilePath -> ByteString -> IO WriteFileResult
|
chatWriteFile :: ChatController -> FilePath -> ByteString -> IO WriteFileResult
|
||||||
chatWriteFile ChatController {random} path s = do
|
chatWriteFile ChatController {random} path s = do
|
||||||
cfArgs <- atomically $ CF.randomArgs random
|
cfArgs <- atomically $ CF.randomArgs random
|
||||||
let file = CryptoFile path $ Just cfArgs
|
chatWriteFile_ (Just cfArgs) path s
|
||||||
either WFError (\_ -> WFResult cfArgs)
|
|
||||||
|
chatWriteFile_ :: Maybe CryptoFileArgs -> FilePath -> ByteString -> IO WriteFileResult
|
||||||
|
chatWriteFile_ cfArgs_ path s = do
|
||||||
|
let file = CryptoFile path cfArgs_
|
||||||
|
either WFError (\_ -> WFResult cfArgs_)
|
||||||
<$> runCatchExceptT (withExceptT show $ CF.writeFile file $ LB.fromStrict s)
|
<$> runCatchExceptT (withExceptT show $ CF.writeFile file $ LB.fromStrict s)
|
||||||
|
|
||||||
|
cChatWriteImage :: StablePtr ChatController -> CLong -> CString -> Ptr Word8 -> CInt -> CBool -> IO CJSONString
|
||||||
|
cChatWriteImage cc maxSize cPath ptr len encrypt = do
|
||||||
|
c <- deRefStablePtr cc
|
||||||
|
path <- peekCString cPath
|
||||||
|
src <- getByteString ptr len
|
||||||
|
cfArgs_ <- if encrypt /= 0 then Just <$> atomically (CF.randomArgs $ random c) else pure Nothing
|
||||||
|
r <-
|
||||||
|
case Picture.decodeResizeable src of
|
||||||
|
Left e -> pure $ WFError e
|
||||||
|
Right (ri, _metadata) -> do
|
||||||
|
let resized = resizeImageToSize False storeMinQuality (fromIntegral maxSize) ri
|
||||||
|
if LB.length resized > fromIntegral maxSize
|
||||||
|
then pure $ WFError "unable to fit"
|
||||||
|
else chatWriteFile_ cfArgs_ path (LB.toStrict resized)
|
||||||
|
newCStringFromLazyBS $ J.encode r
|
||||||
|
where
|
||||||
|
storeMinQuality = 20
|
||||||
|
|
||||||
data ReadFileResult
|
data ReadFileResult
|
||||||
= RFResult {fileSize :: Int}
|
= RFResult {fileSize :: Int}
|
||||||
| RFError {readError :: String}
|
| RFError {readError :: String}
|
||||||
@@ -106,7 +131,7 @@ chatEncryptFile ChatController {random} fromPath toPath =
|
|||||||
encrypt = do
|
encrypt = do
|
||||||
cfArgs <- atomically $ CF.randomArgs random
|
cfArgs <- atomically $ CF.randomArgs random
|
||||||
encryptFile fromPath toPath cfArgs
|
encryptFile fromPath toPath cfArgs
|
||||||
pure cfArgs
|
pure $ Just cfArgs
|
||||||
|
|
||||||
cChatDecryptFile :: CString -> CString -> CString -> CString -> IO CString
|
cChatDecryptFile :: CString -> CString -> CString -> CString -> IO CString
|
||||||
cChatDecryptFile cFromPath cKey cNonce cToPath = do
|
cChatDecryptFile cFromPath cKey cNonce cToPath = do
|
||||||
|
|||||||
@@ -620,7 +620,7 @@ testXFTPFileTransferEncrypted =
|
|||||||
createDirectoryIfMissing True "./tests/tmp/alice/"
|
createDirectoryIfMissing True "./tests/tmp/alice/"
|
||||||
createDirectoryIfMissing True "./tests/tmp/bob/"
|
createDirectoryIfMissing True "./tests/tmp/bob/"
|
||||||
WFResult cfArgs <- chatWriteFile (chatController alice) srcPath src
|
WFResult cfArgs <- chatWriteFile (chatController alice) srcPath src
|
||||||
let fileJSON = LB.unpack $ J.encode $ CryptoFile srcPath $ Just cfArgs
|
let fileJSON = LB.unpack $ J.encode $ CryptoFile srcPath cfArgs
|
||||||
withXFTPServer $ do
|
withXFTPServer $ do
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice ##> ("/_send @2 json [{\"msgContent\":{\"type\":\"file\", \"text\":\"\"}, \"fileSource\": " <> fileJSON <> "}]")
|
alice ##> ("/_send @2 json [{\"msgContent\":{\"type\":\"file\", \"text\":\"\"}, \"fileSource\": " <> fileJSON <> "}]")
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
module LinkPreviewTests where
|
||||||
|
|
||||||
|
import qualified Data.ByteString.Base64.Lazy as LB64
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||||
|
import qualified Codec.Picture as Picture
|
||||||
|
import Control.Logger.Simple
|
||||||
|
import Control.Monad
|
||||||
|
import Simplex.Chat.Image (ResizeableImage (..))
|
||||||
|
import qualified Simplex.Chat.Image as Image
|
||||||
|
import Simplex.Messaging.Util (tshow)
|
||||||
|
import Test.Hspec
|
||||||
|
|
||||||
|
linkPreviewTests :: SpecWith FilePath
|
||||||
|
linkPreviewTests = do
|
||||||
|
fdescribe "Image resize" $ do
|
||||||
|
it "JPG" $ resizeToStrTest "tests/fixtures/test.jpg"
|
||||||
|
it "PNG with alpha" $ resizeToStrTest "tests/fixtures/logo-large-rgba.png"
|
||||||
|
it "PNG without alpha" $ resizeToStrTest "tests/fixtures/preview-issue1.png"
|
||||||
|
|
||||||
|
resizeToStrTest :: FilePath -> FilePath -> IO ()
|
||||||
|
resizeToStrTest inputPath tmp = do
|
||||||
|
(ri@(ResizeableImage imgFormat _img encoder), metadata) <- either error pure =<< Image.readResizeable inputPath
|
||||||
|
logDebug $ tshow (metadata, imgFormat, either (const "png") (const "jpg") encoder)
|
||||||
|
let res = Image.resizeImageToSize True 20 maxSize ri
|
||||||
|
finalSize = LB.length res
|
||||||
|
unless (finalSize <= maxSize) $ error $ "Final size larger than maximum size: " <> show (finalSize, maxSize)
|
||||||
|
let (fmt, b64) = fmap (LB.drop 8) . LB.break (== ';') $ LB.drop 11 res
|
||||||
|
outFile = tmp ++ "/out." ++ LB.unpack fmt
|
||||||
|
either error (LB.writeFile outFile) $ LB64.decode b64
|
||||||
|
Picture.readImageWithMetadata outFile >>= either error (logDebug . tshow . snd)
|
||||||
|
where
|
||||||
|
maxSize = 14000
|
||||||
@@ -282,8 +282,8 @@ testFileCApi fileName tmp = do
|
|||||||
ptr <- mallocBytes $ B.length src
|
ptr <- mallocBytes $ B.length src
|
||||||
putByteString ptr src
|
putByteString ptr src
|
||||||
r <- peekCAString =<< cChatWriteFile cc cPath ptr cLen
|
r <- peekCAString =<< cChatWriteFile cc cPath ptr cLen
|
||||||
Just (WFResult cfArgs@(CFArgs key nonce)) <- jDecode r
|
Just (WFResult cfArgs@(Just (CFArgs key nonce))) <- jDecode r
|
||||||
let encryptedFile = CryptoFile path $ Just cfArgs
|
let encryptedFile = CryptoFile path cfArgs
|
||||||
CF.getFileContentsSize encryptedFile `shouldReturn` fromIntegral (B.length src)
|
CF.getFileContentsSize encryptedFile `shouldReturn` fromIntegral (B.length src)
|
||||||
cKey <- encodedCString key
|
cKey <- encodedCString key
|
||||||
cNonce <- encodedCString nonce
|
cNonce <- encodedCString nonce
|
||||||
@@ -318,8 +318,8 @@ testFileEncryptionCApi fileName tmp = do
|
|||||||
let toPath = tmp </> (fileName <> ".encrypted.pdf")
|
let toPath = tmp </> (fileName <> ".encrypted.pdf")
|
||||||
cToPath <- newCString toPath
|
cToPath <- newCString toPath
|
||||||
r <- peekCAString =<< cChatEncryptFile cc cFromPath cToPath
|
r <- peekCAString =<< cChatEncryptFile cc cFromPath cToPath
|
||||||
Just (WFResult cfArgs@(CFArgs key nonce)) <- jDecode r
|
Just (WFResult cfArgs@(Just (CFArgs key nonce))) <- jDecode r
|
||||||
CF.getFileContentsSize (CryptoFile toPath $ Just cfArgs) `shouldReturn` fromIntegral (B.length src)
|
CF.getFileContentsSize (CryptoFile toPath cfArgs) `shouldReturn` fromIntegral (B.length src)
|
||||||
cKey <- encodedCString key
|
cKey <- encodedCString key
|
||||||
cNonce <- encodedCString nonce
|
cNonce <- encodedCString nonce
|
||||||
let toPath' = tmp </> (fileName <> ".decrypted.pdf")
|
let toPath' = tmp </> (fileName <> ".decrypted.pdf")
|
||||||
|
|||||||
+3
-1
@@ -6,6 +6,7 @@ import ChatTests.Utils (xdescribe'')
|
|||||||
import Control.Logger.Simple
|
import Control.Logger.Simple
|
||||||
import Data.Time.Clock.System
|
import Data.Time.Clock.System
|
||||||
import JSONTests
|
import JSONTests
|
||||||
|
import LinkPreviewTests
|
||||||
import MarkdownTests
|
import MarkdownTests
|
||||||
import MessageBatching
|
import MessageBatching
|
||||||
import MobileTests
|
import MobileTests
|
||||||
@@ -22,7 +23,7 @@ import WebRTCTests
|
|||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
setLogLevel LogError
|
setLogLevel LogDebug
|
||||||
withGlobalLogging logCfg . hspec $ do
|
withGlobalLogging logCfg . hspec $ do
|
||||||
describe "Schema dump" schemaDumpTest
|
describe "Schema dump" schemaDumpTest
|
||||||
describe "SimpleX chat markdown" markdownTests
|
describe "SimpleX chat markdown" markdownTests
|
||||||
@@ -40,6 +41,7 @@ main = do
|
|||||||
xdescribe'' "SimpleX Broadcast bot" broadcastBotTests
|
xdescribe'' "SimpleX Broadcast bot" broadcastBotTests
|
||||||
xdescribe'' "SimpleX Directory service bot" directoryServiceTests
|
xdescribe'' "SimpleX Directory service bot" directoryServiceTests
|
||||||
describe "Remote session" remoteTests
|
describe "Remote session" remoteTests
|
||||||
|
around testBracket $ describe "Link preview" linkPreviewTests
|
||||||
where
|
where
|
||||||
testBracket test = withSmpServer $ tmpBracket test
|
testBracket test = withSmpServer $ tmpBracket test
|
||||||
tmpBracket test = do
|
tmpBracket test = do
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Reference in New Issue
Block a user