mirror of
https://github.com/urbit/shrub.git
synced 2025-01-02 17:43:32 +03:00
Merge branch 'master' into hm/fix-popover-routes
This commit is contained in:
commit
f6533823f6
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@ -116,3 +116,24 @@ jobs:
|
||||
- run: nix-build -A hs.urbit-king.components.exes.urbit-king --arg enableStatic true
|
||||
- run: nix-build -A hs-checks
|
||||
- run: nix-build shell.nix
|
||||
|
||||
mingw:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: C:\msys64\msys2_shell.cmd -mingw64 -defterm -no-start -here -c ". <(cygpath '{0}')"
|
||||
working-directory: ./pkg/urbit
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
# echo suppresses pacman prompt
|
||||
- run: echo|./configure
|
||||
env:
|
||||
CACHIX_CACHE: ares
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
|
||||
- run: make build/urbit build/urbit-worker
|
||||
- run: build/urbit -l -d -B ../../bin/solid.pill -F bus && curl -f --data '{"source":{"dojo":"+hood/exit"},"sink":{"app":"hood"}}' http://localhost:12321
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -55,7 +55,11 @@ release/
|
||||
dist/
|
||||
out/
|
||||
work/
|
||||
pkg/*/*.a
|
||||
*.o
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Landscape Dev
|
||||
urbitrc
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e0af91e5c51359719aaa943f37a1e953989c786412616b18fbaa0addb2cf0740
|
||||
size 10272514
|
||||
oid sha256:9a56f675d2a6c5dafa92a9e2d55040d994f3d3d27a1ed827bd87d1158b1e69d0
|
||||
size 3749183
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:23d8235b19a3404e0bfbed54aa56a018255beb1f33457e37f521bc0763b4d0eb
|
||||
size 6245506
|
||||
oid sha256:f50aee74e4f3dd6685d36520bbc924ab94d3d47a7bc86e649882e58ab069e7dd
|
||||
size 991930
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5159d6516c0b3d12b3c7f39f434ab769e99392dc94aa43add32bb2a91455c73a
|
||||
size 6121099
|
||||
oid sha256:8229a2dc1908d4bb322a3300e68f79e79e3352507b8ef68d40e802bcbdb19550
|
||||
size 5437325
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4427b6e4a925502fe2e63087e190dfe0c77f75644dfe31a306de64d269b128f2
|
||||
size 14661883
|
||||
oid sha256:618a74c199baa6d52ae9eea8c40f4f5b15e95b441e743d0f989275321e5b0703
|
||||
size 7299622
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8baf284490d8c7cfbad2481f1ef0d17a6bb05200bc179b78c1a8718461756a06
|
||||
size 12941119
|
||||
oid sha256:d8d387759fe4830fcc09a1fc7b80d52e61327d518f7eb0713697aec1819eacf7
|
||||
size 5608210
|
||||
|
12
default.nix
12
default.nix
@ -86,19 +86,11 @@ let
|
||||
# Local vendored packages defined in ./pkg.
|
||||
# For non-vendored nixpkgs specific package overrides, see ./nix/overlays.
|
||||
pkgsLocal = {
|
||||
argon2u = callPackage ./nix/pkgs/argon2u { };
|
||||
|
||||
ca-bundle = callPackage ./nix/pkgs/ca-bundle { };
|
||||
|
||||
ed25519 = callPackage ./nix/pkgs/ed25519 { };
|
||||
|
||||
ent = callPackage ./nix/pkgs/ent { };
|
||||
|
||||
ge-additions = callPackage ./nix/pkgs/ge-additions { };
|
||||
|
||||
libaes_siv = callPackage ./nix/pkgs/libaes_siv { };
|
||||
|
||||
libscrypt = callPackage ./nix/pkgs/libscrypt { };
|
||||
libaes_siv = callPackage ./nix/pkgs/libaes_siv { inherit (pkgsNative) cmake; };
|
||||
|
||||
murmur3 = callPackage ./nix/pkgs/murmur3 { };
|
||||
|
||||
@ -118,6 +110,8 @@ let
|
||||
|
||||
urbit = callPackage ./nix/pkgs/urbit { inherit enableStatic; };
|
||||
|
||||
urcrypt = callPackage ./nix/pkgs/urcrypt { inherit enableStatic; };
|
||||
|
||||
docker-image = callPackage ./nix/pkgs/docker-image { };
|
||||
|
||||
hs = callPackage ./nix/pkgs/hs {
|
||||
|
@ -11,6 +11,11 @@ in {
|
||||
outputs = [ "out" "dev" "lib" ];
|
||||
});
|
||||
|
||||
secp256k1 = prev.secp256k1.overrideAttrs (_attrs: {
|
||||
version = final.sources.secp256k1.rev;
|
||||
src = final.sources.secp256k1;
|
||||
});
|
||||
|
||||
libsigsegv = prev.libsigsegv.overrideAttrs (attrs: {
|
||||
patches = optionalList attrs.patches ++ [
|
||||
../pkgs/libsigsegv/disable-stackvma_fault-linux-arm.patch
|
||||
|
@ -1,30 +0,0 @@
|
||||
{ stdenv, sources, enableParallelBuilding ? true }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "argon2u";
|
||||
version = sources.argon2u.rev;
|
||||
src = sources.argon2u;
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace Makefile --replace 'ar rcs' '$(AR) rcs'
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
make libargon2.a
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/{lib,include}
|
||||
cp libargon2.a $out/lib/
|
||||
cp include/argon2.h $out/include/
|
||||
cp ./src/blake2/*.h $out/include/
|
||||
'';
|
||||
|
||||
makeFlags = [
|
||||
"AR=${stdenv.cc.targetPrefix}ar" # Fix cross-compilation
|
||||
];
|
||||
|
||||
NO_THREADS = true;
|
||||
|
||||
inherit enableParallelBuilding;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{ stdenv, sources }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "ed25519";
|
||||
version = sources.ed25519.rev;
|
||||
src = sources.ed25519;
|
||||
|
||||
buildPhase = ''
|
||||
CFLAGS="-O3 -Wall -I$src/src"
|
||||
|
||||
for f in $(find src -type f -name '*.c'); do
|
||||
$CC $CFLAGS -c $f -o "''${f//\//_}.o"
|
||||
done
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/{lib,include}
|
||||
$AR rcs $out/lib/libed25519.a *.o
|
||||
cp $src/src/*.h $out/include/
|
||||
'';
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{ lib, stdenv, ed25519, enableParallelBuilding ? true }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "ge-additions";
|
||||
src = lib.cleanSource ../../../pkg/ge-additions;
|
||||
|
||||
buildInputs = [ ed25519 ];
|
||||
|
||||
installFlags = [ "PREFIX=$(out)" ];
|
||||
|
||||
inherit enableParallelBuilding;
|
||||
}
|
||||
|
34
nix/pkgs/libaes_siv/cmakefiles_static.patch
Normal file
34
nix/pkgs/libaes_siv/cmakefiles_static.patch
Normal file
@ -0,0 +1,34 @@
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -5,6 +5,8 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
|
||||
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
+
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Warning: don't use the UB sanitizer in production builds. It can introduce timing side-channels
|
||||
@@ -31,10 +33,12 @@ endif(NOT DISABLE_DOCS)
|
||||
configure_file(config.h.in config.h)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
+if(BUILD_SHARED_LIBS)
|
||||
add_library(aes_siv SHARED aes_siv.c)
|
||||
target_include_directories(aes_siv PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(aes_siv ${OPENSSL_CRYPTO_LIBRARY})
|
||||
set_target_properties(aes_siv PROPERTIES VERSION "1.0.1" SOVERSION 1)
|
||||
+endif()
|
||||
|
||||
add_library(aes_siv_static STATIC aes_siv.c)
|
||||
target_include_directories(aes_siv_static PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
@@ -63,7 +67,9 @@ endif(ENABLE_SANITIZER)
|
||||
add_executable(bench EXCLUDE_FROM_ALL bench.c)
|
||||
target_link_libraries(bench aes_siv_static)
|
||||
|
||||
+if(BUILD_SHARED_LIBS)
|
||||
install(TARGETS aes_siv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
+endif()
|
||||
install(TARGETS aes_siv_static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(FILES aes_siv.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
@ -1,12 +1,17 @@
|
||||
{ lib, stdenv, openssl, enableParallelBuilding ? true }:
|
||||
{ stdenv, sources, cmake, openssl, enableParallelBuilding ? true }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "libaes_siv";
|
||||
src = lib.cleanSource ../../../pkg/libaes_siv;
|
||||
version = sources.libaes_siv.rev;
|
||||
src = sources.libaes_siv;
|
||||
patches = [ ./cmakefiles_static.patch ];
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
buildInputs = [ openssl ];
|
||||
|
||||
installFlags = [ "PREFIX=$(out)" ];
|
||||
cmakeFlags = [
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
];
|
||||
|
||||
inherit enableParallelBuilding;
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
{ stdenv, sources }:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "libscrypt";
|
||||
version = sources.libscrypt.rev;
|
||||
src = sources.libscrypt;
|
||||
|
||||
buildPhase = ''
|
||||
sources=" \
|
||||
crypto_scrypt-check \
|
||||
crypto_scrypt-hash \
|
||||
crypto_scrypt-hexconvert \
|
||||
crypto_scrypt-nosse \
|
||||
crypto-mcf \
|
||||
crypto-scrypt-saltgen \
|
||||
slowequals \
|
||||
sha256 \
|
||||
b64 \
|
||||
"
|
||||
|
||||
CFLAGS="-I$src -Wall -ffast-math -O3 -D_FORTIFY_SOURCE=2 -fstack-protector"
|
||||
|
||||
for s in $sources; do
|
||||
$CC $CFLAGS -c $src/$s.c -o $s.o
|
||||
done
|
||||
|
||||
$AR rcs libscrypt.a *.o
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/{lib,include}
|
||||
cp libscrypt.a $out/lib
|
||||
cp $src/*.h $out/include/
|
||||
'';
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
{ lib, stdenv, coreutils, pkgconfig, argon2u, cacert, ca-bundle, curlMinimal
|
||||
, ed25519, ent, ge-additions, gmp, h2o, herb, ivory, libaes_siv, libscrypt
|
||||
, libsigsegv, libuv, lmdb, murmur3, openssl, secp256k1, softfloat3, zlib
|
||||
, enableStatic ? stdenv.hostPlatform.isStatic, enableDebug ? false
|
||||
, doCheck ? true, enableParallelBuilding ? true, dontStrip ? true }:
|
||||
{ lib, stdenv, coreutils, pkgconfig # build/env
|
||||
, cacert, ca-bundle, ivory # codegen
|
||||
, curlMinimal, ent, gmp, h2o, libsigsegv, libuv, lmdb # libs
|
||||
, murmur3, openssl, softfloat3, urcrypt, zlib #
|
||||
, enableStatic ? stdenv.hostPlatform.isStatic # opts
|
||||
, enableDebug ? false
|
||||
, doCheck ? true
|
||||
, enableParallelBuilding ? true
|
||||
, dontStrip ? true }:
|
||||
|
||||
let
|
||||
|
||||
@ -19,30 +23,23 @@ in stdenv.mkDerivation {
|
||||
nativeBuildInputs = [ pkgconfig ];
|
||||
|
||||
buildInputs = [
|
||||
argon2u
|
||||
cacert
|
||||
ca-bundle
|
||||
curlMinimal
|
||||
ed25519
|
||||
ent
|
||||
ge-additions
|
||||
gmp
|
||||
h2o
|
||||
ivory.header
|
||||
libaes_siv
|
||||
libscrypt
|
||||
libsigsegv
|
||||
libuv
|
||||
lmdb
|
||||
murmur3
|
||||
openssl
|
||||
secp256k1
|
||||
softfloat3
|
||||
urcrypt
|
||||
zlib
|
||||
];
|
||||
|
||||
checkInputs = [ herb ];
|
||||
|
||||
# Ensure any `/usr/bin/env bash` shebang is patched.
|
||||
postPatch = ''
|
||||
patchShebangs ./configure
|
||||
@ -56,9 +53,14 @@ in stdenv.mkDerivation {
|
||||
cp ./build/urbit-worker $out/bin/urbit-worker
|
||||
'';
|
||||
|
||||
dontDisableStatic = enableStatic;
|
||||
|
||||
configureFlags = if enableStatic
|
||||
then [ "--disable-shared" "--enable-static" ]
|
||||
else [];
|
||||
|
||||
CFLAGS = [ (if enableDebug then "-O0" else "-O3") "-g" ]
|
||||
++ lib.optionals (!enableDebug) [ "-Werror" ]
|
||||
++ lib.optionals enableStatic [ "-static" ];
|
||||
++ lib.optionals (!enableDebug) [ "-Werror" ];
|
||||
|
||||
MEMORY_DEBUG = enableDebug;
|
||||
CPU_DEBUG = enableDebug;
|
||||
|
21
nix/pkgs/urcrypt/default.nix
Normal file
21
nix/pkgs/urcrypt/default.nix
Normal file
@ -0,0 +1,21 @@
|
||||
{ stdenv, autoreconfHook, pkgconfig
|
||||
, libaes_siv, openssl, secp256k1
|
||||
, enableStatic ? stdenv.hostPlatform.isStatic }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
name = "urcrypt";
|
||||
src = ../../../pkg/urcrypt;
|
||||
|
||||
# XX why are these required for darwin?
|
||||
dontDisableStatic = enableStatic;
|
||||
|
||||
configureFlags = if enableStatic
|
||||
then [ "--disable-shared" "--enable-static" ]
|
||||
else [];
|
||||
|
||||
nativeBuildInputs =
|
||||
[ autoreconfHook pkgconfig ];
|
||||
|
||||
propagatedBuildInputs =
|
||||
[ openssl secp256k1 libaes_siv ];
|
||||
}
|
65
nix/sources-pmnsh.json
Normal file
65
nix/sources-pmnsh.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"curl": {
|
||||
"branch": "master",
|
||||
"description": "A command line tool and library for transferring data with URL syntax",
|
||||
"homepage": "http://curl.se/",
|
||||
"pmnsh": {
|
||||
"include": "include",
|
||||
"lib": "lib/.libs",
|
||||
"prepare": "autoreconf -vfi && ./configure --disable-shared --disable-ldap --disable-rtsp --without-brotli --without-libidn2 --without-libpsl --without-nghttp2 --with-openssl",
|
||||
"make": "-C lib libcurl.la"
|
||||
},
|
||||
"owner": "curl",
|
||||
"repo": "curl",
|
||||
"rev": "curl-7_77_0",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/curl/curl/archive/curl-7_77_0.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"lmdb": {
|
||||
"branch": "mdb.master",
|
||||
"description": "LMDB library",
|
||||
"homepage": "http://www.lmdb.tech/",
|
||||
"pmnsh": {
|
||||
"strip": 2,
|
||||
"make": "liblmdb.a"
|
||||
},
|
||||
"owner": "LMDB",
|
||||
"repo": "lmdb",
|
||||
"rev": "48a7fed59a8aae623deff415dda27097198ca0c1",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/LMDB/lmdb/archive/48a7fed59a8aae623deff415dda27097198ca0c1.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"uv": {
|
||||
"branch": "v1.x",
|
||||
"description": "Cross-platform asynchronous I/O",
|
||||
"homepage": "http://libuv.org/",
|
||||
"pmnsh": {
|
||||
"include": "include",
|
||||
"lib": ".libs",
|
||||
"prepare": "./autogen.sh && ./configure --disable-shared",
|
||||
"make": "libuv.la",
|
||||
"compat": {
|
||||
"m1brew": false
|
||||
}
|
||||
},
|
||||
"owner": "libuv",
|
||||
"repo": "libuv",
|
||||
"rev": "v1.40.0",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/libuv/libuv/archive/v1.40.0.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"ent": {
|
||||
"pmnsh": {
|
||||
"prepare": "./configure"
|
||||
}
|
||||
},
|
||||
"urcrypt": {
|
||||
"pmnsh": {
|
||||
"prepare": "./autogen.sh && ./configure --disable-shared PKG_CONFIG_PATH=../secp256k1 CFLAGS=\"-I../secp256k1/include -I../libaes_siv\" LDFLAGS=-L../libaes_siv",
|
||||
"make": "install"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +1,24 @@
|
||||
{
|
||||
"argon2u": {
|
||||
"branch": "master",
|
||||
"description": "With argon2u. Based off https://github.com/P-H-C/phc-winner-argon2",
|
||||
"homepage": "",
|
||||
"owner": "urbit",
|
||||
"repo": "argon2",
|
||||
"rev": "4da94a611ee62bad87ab2b131ffda3bcc0723d9c",
|
||||
"sha256": "0bqq1hg367l4jkb6cqhxlblpvdbwz3l586qsfakwzfd9wdvnm3yc",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/urbit/argon2/archive/4da94a611ee62bad87ab2b131ffda3bcc0723d9c.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"ed25519": {
|
||||
"branch": "master",
|
||||
"description": "Submodule included by Urbit",
|
||||
"homepage": null,
|
||||
"owner": "urbit",
|
||||
"repo": "ed25519",
|
||||
"rev": "76385f2ebbbc9580a9c236952d68d11d73a6135c",
|
||||
"sha256": "0s1spif4s9lgcwcny3fl2fvpbw6acqn3s8r6qxnrmkd9icgyw4cp",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/urbit/ed25519/archive/76385f2ebbbc9580a9c236952d68d11d73a6135c.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"h2o": {
|
||||
"branch": "master",
|
||||
"description": "H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server",
|
||||
"homepage": "https://h2o.examp1e.net",
|
||||
"pmnsh": {
|
||||
"include": "include",
|
||||
"prepare": "cmake .",
|
||||
"make": "libh2o",
|
||||
"compat": {
|
||||
"mingw": {
|
||||
"prepare": "cmake -G\"MSYS Makefiles\" -DCMAKE_INSTALL_PREFIX=. ."
|
||||
}
|
||||
}
|
||||
},
|
||||
"owner": "h2o",
|
||||
"repo": "h2o",
|
||||
"rev": "v2.2.4",
|
||||
"sha256": "0176x0bzjry19zs074a9i5vhncc842xikmx43wj61jky318nq4w4",
|
||||
"rev": "v2.2.6",
|
||||
"sha256": "0qni676wqvxx0sl0pw9j0ph7zf2krrzqc1zwj73mgpdnsr8rsib7",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/h2o/h2o/archive/v2.2.4.tar.gz",
|
||||
"url": "https://github.com/h2o/h2o/archive/v2.2.6.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"hackage.nix": {
|
||||
@ -59,22 +45,37 @@
|
||||
"url": "https://github.com/input-output-hk/haskell.nix/archive/bbb34dcdf7b90d478002f91713531f418ddf1b53.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"libscrypt": {
|
||||
"libaes_siv": {
|
||||
"branch": "master",
|
||||
"description": null,
|
||||
"homepage": null,
|
||||
"owner": "urbit",
|
||||
"repo": "libscrypt",
|
||||
"rev": "029693ff1cbe4f69d3a2da87d0f4f034f92cc0c2",
|
||||
"sha256": "17pcxypzjmmrvacw45cacvibm6mlr9ip30hy30l1appsnywx679n",
|
||||
"pmnsh": {
|
||||
"compat": {
|
||||
"m1brew": {
|
||||
"prepare": "cmake .",
|
||||
"make": "install CFLAGS=$(pkg-config --cflags openssl)"
|
||||
},
|
||||
"mingw": {
|
||||
"prepare": "cmake -G\"MSYS Makefiles\" -DDISABLE_DOCS:BOOL=ON .",
|
||||
"make": "aes_siv_static"
|
||||
}
|
||||
}
|
||||
},
|
||||
"owner":"dfoxfranke",
|
||||
"repo": "libaes_siv",
|
||||
"rev": "9681279cfaa6e6399bb7ca3afbbc27fc2e19df4b",
|
||||
"sha256": "1g4wy0m5wpqx7z6nillppkh5zki9fkx9rdw149qcxh7mc5vlszzi",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/urbit/libscrypt/archive/029693ff1cbe4f69d3a2da87d0f4f034f92cc0c2.tar.gz",
|
||||
"url": "https://github.com/dfoxfranke/libaes_siv/archive/9681279cfaa6e6399bb7ca3afbbc27fc2e19df4b.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"murmur3": {
|
||||
"branch": "master",
|
||||
"description": null,
|
||||
"homepage": null,
|
||||
"pmnsh": {
|
||||
"make": "static"
|
||||
},
|
||||
"owner": "urbit",
|
||||
"repo": "murmur3",
|
||||
"rev": "71a75d57ca4e7ca0f7fc2fd84abd93595b0624ca",
|
||||
@ -111,6 +112,19 @@
|
||||
"branch": "master",
|
||||
"description": null,
|
||||
"homepage": null,
|
||||
"pmnsh": {
|
||||
"include": "source/include",
|
||||
"compat": {
|
||||
"m1brew": {
|
||||
"lib": "build/template-FAST_INT64",
|
||||
"make": "-C build/template-FAST_INT64 libsoftfloat3.a"
|
||||
},
|
||||
"mingw": {
|
||||
"lib": "build/Win64-MinGW-w64",
|
||||
"make": "-C build/Win64-MinGW-w64 libsoftfloat3.a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"owner": "urbit",
|
||||
"repo": "berkeley-softfloat-3",
|
||||
"rev": "ec4c7e31b32e07aad80e52f65ff46ac6d6aad986",
|
||||
@ -119,6 +133,24 @@
|
||||
"url": "https://github.com/urbit/berkeley-softfloat-3/archive/ec4c7e31b32e07aad80e52f65ff46ac6d6aad986.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"secp256k1": {
|
||||
"branch": "master",
|
||||
"description": "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.",
|
||||
"homepage": null,
|
||||
"pmnsh": {
|
||||
"include": "include",
|
||||
"lib": ".libs",
|
||||
"prepare": "./autogen.sh && ./configure --disable-shared --enable-module-recovery CFLAGS=-DSECP256K1_API=",
|
||||
"make": "libsecp256k1.la"
|
||||
},
|
||||
"owner": "bitcoin-core",
|
||||
"repo": "secp256k1",
|
||||
"rev": "26de4dfeb1f1436dae1fcf17f57bdaa43540f940",
|
||||
"sha256": "03i3nv8d3ci7q9y98q11rrp3rvwdqc0hc0ss0pr6xckybvizsmbb",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/bitcoin-core/secp256k1/archive/26de4dfeb1f1436dae1fcf17f57bdaa43540f940.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"stackage.nix": {
|
||||
"branch": "master",
|
||||
"description": "Automatically generated Nix expressions of Stackage snapshots",
|
||||
|
@ -12,7 +12,7 @@
|
||||
=> |% :: external structures
|
||||
+$ id @tasession :: session id
|
||||
+$ house :: all state
|
||||
$: %7
|
||||
$: %8
|
||||
egg=@u :: command count
|
||||
hoc=(map id session) :: conversations
|
||||
acl=(set ship) :: remote access whitelist
|
||||
@ -65,7 +65,7 @@
|
||||
$~ [%ex *hoon]
|
||||
$% [%ur p=@t] :: http GET request
|
||||
[%ge p=dojo-model] :: generator
|
||||
[%te p=term q=(list dojo-source)] :: thread
|
||||
[%te p=[=desk =term] q=(list dojo-source)] :: thread
|
||||
[%dv p=beak q=path] :: core from source
|
||||
[%ex p=hoon] :: hoon expression
|
||||
[%sa p=mark] :: example mark value
|
||||
@ -224,7 +224,7 @@
|
||||
;~ pose
|
||||
;~(plug (cold %ur lus) parse-url)
|
||||
;~(plug (cold %ge lus) parse-model)
|
||||
;~(plug (cold %te hep) sym (star ;~(pfix ace parse-source)))
|
||||
;~(plug (cold %te hep) parse-thread (star ;~(pfix ace parse-source)))
|
||||
;~(plug (cold %as pam) sym ;~(pfix ace parse-source))
|
||||
;~(plug (cold %do cab) parse-hoon ;~(pfix ace parse-source))
|
||||
parse-value
|
||||
@ -278,6 +278,12 @@
|
||||
(most fas sym)
|
||||
==
|
||||
::
|
||||
++ parse-thread
|
||||
;~ plug
|
||||
;~(pose ;~(sfix sym zap) (easy q.dir))
|
||||
sym
|
||||
==
|
||||
::
|
||||
++ parse-hoon tall:hoon-parser
|
||||
::
|
||||
++ parse-rood
|
||||
@ -693,7 +699,7 @@
|
||||
[%sa mark]
|
||||
[%as mark dy-shown]
|
||||
[%do hoon dy-shown]
|
||||
[%te term (list dy-shown)]
|
||||
[%te [desk term] (list dy-shown)]
|
||||
[%ge [desk path] (list dy-shown) (map term (unit dy-shown))]
|
||||
[%dv beak path]
|
||||
==
|
||||
@ -870,7 +876,7 @@
|
||||
(dy-hand %noun q.cag)
|
||||
::
|
||||
++ dy-wool-poke
|
||||
|= [fil=term src=(list dojo-source)]
|
||||
|= [[=desk =term] src=(list dojo-source)]
|
||||
^+ +>+>
|
||||
?> ?=(~ pux)
|
||||
=/ tid (scot %ta (cat 3 'dojo_' (scot %uv (sham eny.hid))))
|
||||
@ -880,8 +886,9 @@
|
||||
[%pass /wool %agent [our.hid %spider] %watch /thread-result/[tid]]
|
||||
%- he-card
|
||||
=/ =cage :: also sub
|
||||
:: TODO: support threads on other desks
|
||||
[%spider-start !>([~ `tid he-beak fil (dy-some src)])]
|
||||
::TODO would be nice if spider supported starting from paths,
|
||||
:: for semantics/abilities/code closer to generators.
|
||||
[%spider-start !>([~ `tid he-beak(q.dir desk) term (dy-some src)])]
|
||||
[%pass /wool %agent [our.hid %spider] %poke cage]
|
||||
::
|
||||
++ dy-make :: build step
|
||||
@ -1522,16 +1529,17 @@
|
||||
|^ =+ old=!<(house-any ole)
|
||||
=? old ?=(%5 -.old)
|
||||
(house-5-to-6 old)
|
||||
=? old ?=(%6 -.old)
|
||||
(house-6-to-7 old)
|
||||
?> ?=(%7 -.old)
|
||||
=? old ?=(?(%6 %7) -.old)
|
||||
(house-6-7-to-8 +.old)
|
||||
?> ?=(%8 -.old)
|
||||
`..on-init(state old)
|
||||
::
|
||||
+$ house-any $%(house house-6 house-5)
|
||||
+$ house-any $%(house house-7 house-6 house-5)
|
||||
::
|
||||
+$ house-6 :: all state
|
||||
$: %6
|
||||
egg=@u :: command count
|
||||
+$ house-7 [%7 house-6-7]
|
||||
+$ house-6 [%6 house-6-7]
|
||||
+$ house-6-7
|
||||
$: egg=@u :: command count
|
||||
hoc=(map id session-6) :: conversations
|
||||
acl=(set ship) :: remote access whitelist
|
||||
== ::
|
||||
@ -1550,10 +1558,10 @@
|
||||
old=(set term) :: used TLVs
|
||||
buf=tape :: multiline buffer
|
||||
== ::
|
||||
++ house-6-to-7
|
||||
|= old=house-6
|
||||
[%7 egg.old (~(run by hoc.old) session-6-to-7) acl.old]
|
||||
++ session-6-to-7
|
||||
++ house-6-7-to-8
|
||||
|= old=house-6-7
|
||||
[%8 egg.old (~(run by hoc.old) session-6-to-8) acl.old]
|
||||
++ session-6-to-8
|
||||
|= old=session-6
|
||||
~? ?=(^ poy.old) [dap.hid %cancelling-for-load]
|
||||
old(poy ~, -.dir [our.hid %base ud+0])
|
||||
|
@ -551,8 +551,8 @@
|
||||
=. vats (abed lac)
|
||||
?^ rail.rak
|
||||
go
|
||||
~> %slog.(fmt "{<lac>} already installed locally, ignoring")
|
||||
vats
|
||||
~> %slog.(fmt "{<lac>} already installed locally, refreshing")
|
||||
update-running-dudes
|
||||
::
|
||||
++ go
|
||||
=. loc lac
|
||||
|
@ -1587,14 +1587,15 @@
|
||||
:::: ++keccak:crypto :: (2b7) keccak family
|
||||
:: ::::
|
||||
++ keccak
|
||||
~% %kecc ..part ~
|
||||
|%
|
||||
::
|
||||
:: keccak
|
||||
::
|
||||
++ keccak-224 |=(a=octs (keccak 1.152 448 224 a))
|
||||
++ keccak-256 |=(a=octs (keccak 1.088 512 256 a))
|
||||
++ keccak-384 |=(a=octs (keccak 832 768 384 a))
|
||||
++ keccak-512 |=(a=octs (keccak 576 1.024 512 a))
|
||||
++ keccak-224 ~/ %k224 |=(a=octs (keccak 1.152 448 224 a))
|
||||
++ keccak-256 ~/ %k256 |=(a=octs (keccak 1.088 512 256 a))
|
||||
++ keccak-384 ~/ %k384 |=(a=octs (keccak 832 768 384 a))
|
||||
++ keccak-512 ~/ %k512 |=(a=octs (keccak 576 1.024 512 a))
|
||||
::
|
||||
++ keccak (cury (cury hash keccak-f) padding-keccak)
|
||||
::
|
||||
|
@ -21,10 +21,7 @@
|
||||
!> `@ux`(hsh pw salt n r p 64)
|
||||
::
|
||||
++ vectors
|
||||
:: TODO: until scrypt has been jetted, we can only test the
|
||||
:: first vector; the others do not finish in a reasonable
|
||||
:: amount of time.
|
||||
%+ scag 1 ^- (list vector)
|
||||
^- (list vector)
|
||||
:~
|
||||
:*
|
||||
0x0
|
||||
@ -37,8 +34,8 @@
|
||||
==
|
||||
::
|
||||
:*
|
||||
0x7061.7373.776f.7264
|
||||
0x4e61.436c
|
||||
`@ux`'password'
|
||||
`@ux`'NaCl'
|
||||
1.024 8 16
|
||||
0xfdba.be1c.9d34.7200.7856.e719.0d01.e9fe.
|
||||
7c6a.d7cb.c823.7830.e773.7663.4b37.3162.
|
||||
@ -47,8 +44,8 @@
|
||||
==
|
||||
::
|
||||
:*
|
||||
0x70.6c65.6173.656c.6574.6d65.696e
|
||||
0x536f.6469.756d.4368.6c6f.7269.6465
|
||||
`@ux`'pleaseletmein'
|
||||
`@ux`'SodiumChloride'
|
||||
16.384 8 1
|
||||
0x7023.bdcb.3afd.7348.461c.06cd.81fd.38eb.
|
||||
fda8.fbba.904f.8e3e.a9b5.43f6.545d.a1f2.
|
||||
@ -57,8 +54,8 @@
|
||||
==
|
||||
::
|
||||
:*
|
||||
0x70.6c65.6173.656c.6574.6d65.696e
|
||||
0x536f.6469.756d.4368.6c6f.7269.6465
|
||||
`@ux`'pleaseletmein'
|
||||
`@ux`'SodiumChloride'
|
||||
1.048.576 8 1
|
||||
0x2101.cb9b.6a51.1aae.addb.be09.cf70.f881.
|
||||
ec56.8d57.4a2f.fd4d.abe5.ee98.20ad.aa47.
|
||||
|
@ -156,7 +156,7 @@
|
||||
::
|
||||
:- ~
|
||||
:+ %agent wire.in
|
||||
[%fact (validate-mark q.cage.sign.in p.cage.sign.in bowl.strand-input)]
|
||||
[%fact (validate-mark q.q.cage.sign.in p.cage.sign.in bowl.strand-input)]
|
||||
:: run the strand callback
|
||||
::
|
||||
=/ =output (form.eval-form strand-input)
|
||||
|
1
pkg/ent/configure
vendored
1
pkg/ent/configure
vendored
@ -7,6 +7,7 @@ log () {
|
||||
for impl in ENT_GETENTROPY_UNISTD \
|
||||
ENT_GETENTROPY_SYSRANDOM \
|
||||
ENT_GETRANDOM_SYSCALL \
|
||||
ENT_GETENTROPY_BCRYPTGENRANDOM \
|
||||
ENT_DEV_URANDOM
|
||||
do
|
||||
export IMPL=$impl
|
||||
|
@ -57,6 +57,16 @@ int ent_getentropy(void* buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Use `BCryptGenRandom` on Windows ////////////////////////////////////////////
|
||||
|
||||
#elif defined(ENT_GETENTROPY_BCRYPTGENRANDOM)
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
int ent_getentropy(void* buf, size_t len) {
|
||||
return BCryptGenRandom(NULL, (PUCHAR)buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "One of these must be set: ENT_DEV_URANDOM, ENT_GETENTROPY_UNISTD, ENT_GETENTROPY_SYSRANDOM, ENT_GETRANDOM_SYSCALL"
|
||||
#error "One of these must be set: ENT_GETENTROPY_BCRYPTGENRANDOM, ENT_DEV_URANDOM, ENT_GETENTROPY_UNISTD, ENT_GETENTROPY_SYSRANDOM, ENT_GETRANDOM_SYSCALL"
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
io ~(. agentio bowl)
|
||||
pass pass:io
|
||||
cc ~(. +> bowl)
|
||||
++ on-init
|
||||
++ on-init
|
||||
?: =(our.bowl default-ally) `this
|
||||
(on-poke %ally-update-0 !>([%add default-ally]))
|
||||
++ on-save !>(state)
|
||||
@ -37,12 +37,12 @@
|
||||
|= [=mark =vase]
|
||||
^- (quip card _this)
|
||||
?> (team:title [our src]:bowl)
|
||||
|^
|
||||
|^
|
||||
?+ mark (on-poke:def mark vase)
|
||||
%ally-update-0 (ally-update !<(update:ally vase))
|
||||
%alliance-update-0 (alliance-update !<(update:alliance vase))
|
||||
%alliance-update-0 (alliance-update !<(update:alliance vase))
|
||||
::
|
||||
%noun
|
||||
%noun
|
||||
=+ ;;([%add =desk] q.vase)
|
||||
=/ =docket:docket ~(get-docket so:cc desk)
|
||||
=/ =treaty (treaty-from-docket:cc desk docket)
|
||||
@ -69,7 +69,7 @@
|
||||
=- [[(alliance-update:ca:cc update) -.-] +.-]
|
||||
?+ -.update !!
|
||||
::
|
||||
%add
|
||||
%add
|
||||
=, update
|
||||
=. entente (~(put in entente) [ship desk])
|
||||
?. =(our.bowl ship) `this
|
||||
@ -78,7 +78,7 @@
|
||||
=/ =treaty (treaty-from-docket:cc desk docket)
|
||||
=. sovereign (~(put by sovereign) desk treaty)
|
||||
:_ this
|
||||
~[publish warp give]:so
|
||||
[publish warp give]:so
|
||||
::
|
||||
%del
|
||||
=, update
|
||||
@ -93,8 +93,8 @@
|
||||
|= =path
|
||||
^- (quip card _this)
|
||||
?+ path (on-watch:def path)
|
||||
:: syncing
|
||||
[%treaty @ @ ~]
|
||||
:: syncing
|
||||
[%treaty @ @ ~]
|
||||
=/ =ship (slav %p i.t.path)
|
||||
=* desk i.t.t.path
|
||||
?: =(our.bowl ship)
|
||||
@ -105,6 +105,12 @@
|
||||
?> =(our.bowl src.bowl)
|
||||
=. direct (~(put in direct) [ship desk])
|
||||
:_(this (drop ~(safe-watch tr:cc [ship desk])))
|
||||
::
|
||||
[%treaties ~]
|
||||
:_ this
|
||||
::NOTE this assumes that all treaties in sovereign are also
|
||||
:: present in the treaties map
|
||||
(fact-init:io (treaty-update:cg:cc %ini treaties))^~
|
||||
::
|
||||
[%alliance ~]
|
||||
:_ this
|
||||
@ -141,15 +147,15 @@
|
||||
``(treaty:cg:cc (~(got by treaties) [ship desk]))
|
||||
==
|
||||
::
|
||||
++ on-agent
|
||||
++ on-agent
|
||||
|= [=wire =sign:agent:gall]
|
||||
^- (quip card _this)
|
||||
=* ship src.bowl
|
||||
|^
|
||||
|^
|
||||
?+ wire (on-agent:def wire sign)
|
||||
[%ally @ ~] ?>(=(src.bowl (slav %p i.t.wire)) take-ally)
|
||||
::
|
||||
[%treaty @ @ ~]
|
||||
[%treaty @ @ ~]
|
||||
=* desk i.t.t.wire
|
||||
?> =(ship (slav %p i.t.wire))
|
||||
(take-treaty desk)
|
||||
@ -171,8 +177,8 @@
|
||||
%fact
|
||||
?. =(%alliance-update-0 p.cage.sign) `this
|
||||
=+ !<(=update:alliance q.cage.sign)
|
||||
=^ cards allies
|
||||
?- -.update
|
||||
=^ cards allies
|
||||
?- -.update
|
||||
::
|
||||
%ini
|
||||
:_ (~(put by allies) src.bowl init.update)
|
||||
@ -180,7 +186,7 @@
|
||||
|= [s=^ship =desk]
|
||||
~(safe-watch tr:cc s desk)
|
||||
::
|
||||
%add
|
||||
%add
|
||||
:_ (~(put ju allies) src.bowl [ship desk]:update)
|
||||
(drop ~(safe-watch tr:cc [ship desk]:update))
|
||||
|
||||
@ -195,31 +201,31 @@
|
||||
::
|
||||
++ take-treaty
|
||||
|= =desk
|
||||
=* tr ~(. tr:cc ship desk)
|
||||
?+ -.sign (on-agent:def wire sign)
|
||||
::
|
||||
:: rewatch only if we aren't source
|
||||
:: this would cause a potential kick-rewatch loop otherwise
|
||||
::
|
||||
%kick
|
||||
%kick
|
||||
:_ this
|
||||
?: =(our.bowl src.bowl) ~
|
||||
~(watch tr:cc ship desk)^~
|
||||
?: =(our.bowl ship) ~
|
||||
~[watch:tr]
|
||||
::
|
||||
%watch-ack
|
||||
?~ p.sign `this
|
||||
=: treaties (~(del by treaties) ship desk)
|
||||
direct (~(del in direct) ship desk)
|
||||
==
|
||||
%- (slog leaf+"Withdrew from treaty {<ship>}/{<desk>}" u.p.sign)
|
||||
:_ this
|
||||
(kick-only:io our.bowl /treaty/(scot %p ship)/[desk] ~)^~
|
||||
%- (slog leaf+"treaty: withdrew from {<ship>}/{<desk>}" u.p.sign)
|
||||
[gone:tr this]
|
||||
::
|
||||
%fact
|
||||
?. =(%treaty-0 p.cage.sign) `this
|
||||
=+ !<(=treaty q.cage.sign)
|
||||
?> =([ship desk] [ship desk]:treaty)
|
||||
=. treaties (~(put by treaties) [ship desk]:treaty treaty)
|
||||
[~(give tr ship desk)^~ this]
|
||||
[give:tr this]
|
||||
==
|
||||
--
|
||||
::
|
||||
@ -249,7 +255,7 @@
|
||||
=/ =treaty (treaty-from-docket:cc desk docket)
|
||||
=. sovereign (~(put by sovereign) desk treaty)
|
||||
=* so ~(. so:cc desk)
|
||||
:_(this [give warp ~]:so)
|
||||
:_(this [warp give]:so)
|
||||
--
|
||||
|
||||
::
|
||||
@ -269,7 +275,7 @@
|
||||
++ al
|
||||
|_ =ship
|
||||
++ pass ~(. ^pass /ally/(scot %p ship))
|
||||
++ watch (watch:pass [ship dap.bowl] /alliance)
|
||||
++ watch (watch:pass [ship dap.bowl] /alliance)
|
||||
++ leave (leave:pass ship dap.bowl)
|
||||
--
|
||||
:: +cg: Cage construction
|
||||
@ -285,7 +291,7 @@
|
||||
|%
|
||||
++ watch-docket (~(watch-our pass /docket) %docket /dockets)
|
||||
++ ally-update |=(=update:ally (fact:io (ally-update:cg update) /allies ~))
|
||||
++ alliance-update
|
||||
++ alliance-update
|
||||
|=(=update:alliance (fact:io (alliance-update:cg update) /alliance ~))
|
||||
--
|
||||
:: +tr: engine for treaties
|
||||
@ -298,9 +304,17 @@
|
||||
++ watching (~(has by wex.bowl) [path dock])
|
||||
++ safe-watch `(unit card)`?:(|(watching =(our.bowl ship)) ~ `watch)
|
||||
++ leave (leave:pass dock)
|
||||
++ give
|
||||
++ gone
|
||||
^- (list card)
|
||||
:~ (fact:io (treaty-update:cg %del ship desk) /treaties ~)
|
||||
(kick-only:io our.bowl path ~)
|
||||
==
|
||||
++ give
|
||||
^- (list card)
|
||||
=/ t=treaty (~(got by treaties) ship desk)
|
||||
(fact:io (treaty:cg t) /treaties path ~)
|
||||
:~ (fact:io (treaty-update:cg %add t) /treaties ~)
|
||||
(fact:io (treaty:cg t) path ~)
|
||||
==
|
||||
--
|
||||
:: +so: engine for sovereign treaties
|
||||
++ so
|
||||
@ -314,8 +328,15 @@
|
||||
++ kick
|
||||
(kick:io path ~)
|
||||
++ give
|
||||
:: notably gives on the /treaties path, like +give:tr does.
|
||||
:: this should not give duplicate facts, because sovereign treaties
|
||||
:: are handled in this core, not as "normal"/foreign treaties.
|
||||
::
|
||||
^- (list card)
|
||||
=/ t=treaty (~(got by sovereign) desk)
|
||||
(fact:io (treaty:cg t) /sovereign path ~)
|
||||
:~ (fact:io (treaty-update:cg %add t) /treaties ~)
|
||||
(fact:io (treaty:cg t) path ~)
|
||||
==
|
||||
++ publish
|
||||
(poke-our:pass %hood kiln-permission+!>([desk / &]))
|
||||
--
|
||||
|
@ -1,7 +1,7 @@
|
||||
:~ title+'System'
|
||||
info+'An app launcher for Urbit.'
|
||||
color+0xee.5432
|
||||
glob-http+['https://bootstrap.urbit.org/glob-0v1.0b7ou.danvu.2847h.pj7dp.5in88.glob' 0v1.0b7ou.danvu.2847h.pj7dp.5in88]
|
||||
glob-http+['https://bootstrap.urbit.org/glob-0v3.gvak7.ju252.1t3vv.or3ki.kvhlt.glob' 0v3.gvak7.ju252.1t3vv.or3ki.kvhlt]
|
||||
::glob-ames+~zod^0v0
|
||||
base+'grid'
|
||||
version+[0 0 1]
|
||||
|
7
pkg/garden/gen/treaty/unally.hoon
Normal file
7
pkg/garden/gen/treaty/unally.hoon
Normal file
@ -0,0 +1,7 @@
|
||||
:: :treaty|unally: Stop syncing treaty data from ship
|
||||
::
|
||||
:- %say
|
||||
|= $: [now=@da eny=@uvJ bec=beak]
|
||||
[[=ship ~] ~]
|
||||
==
|
||||
[%ally-update-0 %del ship]
|
@ -77,5 +77,16 @@
|
||||
==
|
||||
==
|
||||
--
|
||||
++ dejs
|
||||
=, dejs:format
|
||||
|%
|
||||
++ ship (su ;~(pfix sig fed:ag))
|
||||
++ ally-update
|
||||
^- $-(json update:ally)
|
||||
%- of
|
||||
:~ add+ship
|
||||
del+ship
|
||||
==
|
||||
--
|
||||
--
|
||||
|
||||
|
@ -10,5 +10,6 @@
|
||||
++ grab
|
||||
|%
|
||||
++ noun update:ally
|
||||
++ json ally-update:dejs:treat
|
||||
--
|
||||
--
|
||||
|
@ -32,6 +32,6 @@
|
||||
;< =bowl:spider bind:m get-bowl:strandio
|
||||
;< =cage bind:m
|
||||
(watch-one:strandio /glob/(scot %da now.bowl) [ship %docket] /glob/[base]/(scot %uv hash))
|
||||
?> ?=(%glob p.cage)
|
||||
?> ?=(%glob-0 p.cage)
|
||||
(pure:m q.cage)
|
||||
--
|
||||
|
@ -1,20 +0,0 @@
|
||||
CC ?= cc
|
||||
AR ?= ar
|
||||
PREFIX ?= ./out
|
||||
|
||||
################################################################################
|
||||
|
||||
.PHONY: all test install clean
|
||||
|
||||
all: ge-additions.c ge-additions.h
|
||||
$(CC) $(CFLAGS) -O3 -Wall -Werror -pedantic -std=gnu99 -c ge-additions.c
|
||||
$(AR) rcs libge-additions.a ge-additions.o
|
||||
|
||||
install: all
|
||||
@mkdir -p $(PREFIX)/lib/
|
||||
@mkdir -p $(PREFIX)/include/
|
||||
cp libge-additions.a $(PREFIX)/lib/
|
||||
cp ge-additions.h $(PREFIX)/include/
|
||||
|
||||
clean:
|
||||
rm -rf ./out
|
@ -1,8 +0,0 @@
|
||||
let
|
||||
|
||||
pkgs = import ../../default.nix { };
|
||||
|
||||
in pkgs.shellFor {
|
||||
name = "ge-additions";
|
||||
packages = ps: [ ps.ge-additions ];
|
||||
}
|
25
pkg/grid/package-lock.json
generated
25
pkg/grid/package-lock.json
generated
@ -1166,6 +1166,11 @@
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -3601,12 +3606,22 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.chunk": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz",
|
||||
"integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw="
|
||||
},
|
||||
"lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@ -5285,6 +5300,16 @@
|
||||
"isobject": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"urbit-ob": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/urbit-ob/-/urbit-ob-5.0.1.tgz",
|
||||
"integrity": "sha512-qGNAwu87XNkW3g8ah4fUwmh2EKXtsdhEbyEiE5qX4Op17rhLH3HSkvu8g9z+MhqX51Uz9sf8ktvqJj/IRwETIQ==",
|
||||
"requires": {
|
||||
"bn.js": "^4.11.8",
|
||||
"lodash.chunk": "^4.2.0",
|
||||
"lodash.isequal": "^4.5.0"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
|
@ -39,6 +39,7 @@
|
||||
"react-error-boundary": "^3.1.3",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"slugify": "^1.6.0",
|
||||
"urbit-ob": "^5.0.1",
|
||||
"zustand": "^3.5.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
3
pkg/grid/src/global.d.ts
vendored
Normal file
3
pkg/grid/src/global.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare module 'urbit-ob' {
|
||||
export function isValidPatp(patp: string): boolean;
|
||||
}
|
@ -3,7 +3,7 @@ import { RouteComponentProps } from 'react-router-dom';
|
||||
import fuzzy from 'fuzzy';
|
||||
import { Treaty } from '@urbit/api';
|
||||
import { ShipName } from '../../components/ShipName';
|
||||
import useDocketState, { useAllyTreaties } from '../../state/docket';
|
||||
import useDocketState, { useAllyTreaties, useAllies } from '../../state/docket';
|
||||
import { useLeapStore } from '../Nav';
|
||||
import { AppList } from '../../components/AppList';
|
||||
import { addRecentDev } from './Home';
|
||||
@ -18,6 +18,19 @@ export const Apps = ({ match }: AppsProps) => {
|
||||
}));
|
||||
const provider = match?.params.ship;
|
||||
const treaties = useAllyTreaties(provider);
|
||||
const allies = useAllies();
|
||||
const isAllied = provider in allies;
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.keys(allies).length > 0 && !isAllied) {
|
||||
useDocketState
|
||||
.getState()
|
||||
.addAlly(provider)
|
||||
.then(() => {
|
||||
return useDocketState.getState().fetchAllyTreaties(provider);
|
||||
});
|
||||
}
|
||||
}, [allies, isAllied, provider]);
|
||||
const results = useMemo(() => {
|
||||
if (!treaties) {
|
||||
return undefined;
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import fuzzy from 'fuzzy';
|
||||
import { Provider } from '@urbit/api';
|
||||
import { Provider, deSig } from '@urbit/api';
|
||||
import * as ob from 'urbit-ob';
|
||||
import { MatchItem, useLeapStore } from '../Nav';
|
||||
import { useAllies, useCharges } from '../../state/docket';
|
||||
import { ProviderList } from '../../components/ProviderList';
|
||||
@ -53,19 +54,34 @@ export const Providers = ({ match }: ProvidersProps) => {
|
||||
: [],
|
||||
[charges, search]
|
||||
);
|
||||
const results = useMemo(
|
||||
() =>
|
||||
allies
|
||||
? fuzzy
|
||||
.filter(
|
||||
search,
|
||||
Object.entries(allies).map(([ship]) => ship)
|
||||
)
|
||||
.sort(fuzzySort(search))
|
||||
.map((el) => ({ shipName: el.original, ...contacts[el.original] }))
|
||||
: [],
|
||||
[allies, search, contacts]
|
||||
);
|
||||
|
||||
const patp = `~${deSig(search) || ''}`;
|
||||
const isValidPatp = ob.isValidPatp(patp);
|
||||
|
||||
const results = useMemo(() => {
|
||||
if (!allies) {
|
||||
return [];
|
||||
}
|
||||
const exact =
|
||||
isValidPatp && !Object.keys(allies).includes(patp)
|
||||
? [
|
||||
{
|
||||
shipName: patp,
|
||||
...contacts[patp]
|
||||
}
|
||||
]
|
||||
: [];
|
||||
return [
|
||||
...exact,
|
||||
...fuzzy
|
||||
.filter(
|
||||
search,
|
||||
Object.entries(allies).map(([ship]) => ship)
|
||||
)
|
||||
.sort(fuzzySort(search))
|
||||
.map((el) => ({ shipName: el.original, ...contacts[el.original] }))
|
||||
];
|
||||
}, [allies, search, contacts]);
|
||||
|
||||
const count = results?.length;
|
||||
|
||||
@ -87,11 +103,22 @@ export const Providers = ({ match }: ProvidersProps) => {
|
||||
}))
|
||||
: [];
|
||||
|
||||
const newProviderMatches = isValidPatp
|
||||
? [
|
||||
{
|
||||
url: `/leap/search/${patp}/apps`,
|
||||
value: patp,
|
||||
display: patp,
|
||||
openInNewTab: false
|
||||
}
|
||||
]
|
||||
: [];
|
||||
|
||||
useLeapStore.setState({
|
||||
matches: ([] as MatchItem[]).concat(appMatches, providerMatches)
|
||||
matches: ([] as MatchItem[]).concat(appMatches, providerMatches, newProviderMatches)
|
||||
});
|
||||
}
|
||||
}, [results]);
|
||||
}, [results, patp, isValidPatp]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -1,4 +1,4 @@
|
||||
import create from 'zustand';
|
||||
import create, { SetState } from 'zustand';
|
||||
import produce from 'immer';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { omit, pick } from 'lodash';
|
||||
@ -15,11 +15,14 @@ import {
|
||||
Treaties,
|
||||
chadIsRunning,
|
||||
AllyUpdateIni,
|
||||
AllyUpdateNew,
|
||||
TreatyUpdateIni,
|
||||
TreatyUpdate,
|
||||
docketInstall,
|
||||
ChargeUpdate,
|
||||
kilnRevive,
|
||||
kilnSuspend
|
||||
kilnSuspend,
|
||||
allyShip
|
||||
} from '@urbit/api';
|
||||
import api from './api';
|
||||
import { mockAllies, mockCharges, mockTreaties } from './mock-data';
|
||||
@ -50,6 +53,9 @@ interface DocketState {
|
||||
toggleDocket: (desk: string) => Promise<void>;
|
||||
installDocket: (ship: string, desk: string) => Promise<number | void>;
|
||||
uninstallDocket: (desk: string) => Promise<number | void>;
|
||||
//
|
||||
addAlly: (ship: string) => Promise<void>;
|
||||
set: SetState<DocketState>;
|
||||
}
|
||||
|
||||
const useDocketState = create<DocketState>((set, get) => ({
|
||||
@ -151,6 +157,12 @@ const useDocketState = create<DocketState>((set, get) => ({
|
||||
treaties: useMockData ? normalizeDockets(mockTreaties) : {},
|
||||
charges: {},
|
||||
allies: useMockData ? mockAllies : {},
|
||||
addAlly: async (ship) => {
|
||||
get().set((draft) => {
|
||||
draft.allies[ship] = [];
|
||||
});
|
||||
await api.poke(allyShip(ship));
|
||||
},
|
||||
set
|
||||
}));
|
||||
|
||||
@ -199,6 +211,38 @@ api.subscribe({
|
||||
}
|
||||
});
|
||||
|
||||
api.subscribe({
|
||||
app: 'treaty',
|
||||
path: '/treaties',
|
||||
event: (data: TreatyUpdate) => {
|
||||
useDocketState.getState().set((draft) => {
|
||||
if ('add' in data) {
|
||||
const { ship, desk } = data.add;
|
||||
const treaty = normalizeDocket(data.add, desk);
|
||||
draft.treaties[`${ship}/${desk}`] = treaty;
|
||||
}
|
||||
|
||||
if ('ini' in data) {
|
||||
const treaties = normalizeDockets(data.ini);
|
||||
draft.treaties = { ...draft.treaties, ...treaties };
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
api.subscribe({
|
||||
app: 'treaty',
|
||||
path: '/allies',
|
||||
event: (data: AllyUpdateNew) => {
|
||||
useDocketState.getState().set((draft) => {
|
||||
if ('new' in data) {
|
||||
const { ship, alliance } = data.new;
|
||||
draft.allies[ship] = alliance;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const selCharges = (s: DocketState) => {
|
||||
return s.charges;
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ instance FromNoun Pass where
|
||||
-- seed. These aren't actually private keys, but public/private keypairs which
|
||||
-- can be derived from these seeds.
|
||||
data Ring = Ring { ringSign :: BS.ByteString, ringCrypt :: BS.ByteString }
|
||||
deriving (Eq)
|
||||
deriving (Eq, Ord)
|
||||
|
||||
instance ToNoun Ring where
|
||||
toNoun Ring{..} =
|
||||
@ -117,6 +117,36 @@ data Seed = Seed
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
|
||||
data Germs = Germs
|
||||
{ gShip :: Ship
|
||||
, gFeed :: [Germ]
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
|
||||
data Germ = Germ
|
||||
{ gLife :: Life
|
||||
, gRing :: Ring
|
||||
}
|
||||
deriving (Eq, Ord, Show)
|
||||
|
||||
data Feed
|
||||
= Feed0 Seed
|
||||
| Feed1 Germs
|
||||
deriving (Eq, Show)
|
||||
|
||||
-- NOTE reify type environment
|
||||
$(pure [])
|
||||
|
||||
instance ToNoun Feed where
|
||||
toNoun = \case
|
||||
Feed0 s -> $(deriveToNounFunc ''Seed) s
|
||||
Feed1 s -> C (C (A 1) (A 0)) $ $(deriveToNounFunc ''Germs) s
|
||||
|
||||
instance FromNoun Feed where
|
||||
parseNoun = \case
|
||||
(C (C (A 1) (A 0)) s) -> Feed1 <$> $(deriveFromNounFunc ''Germs) s
|
||||
n -> Feed0 <$> $(deriveFromNounFunc ''Seed) n
|
||||
|
||||
type Public = (Life, HoonMap Life Pass)
|
||||
|
||||
data Dnses = Dnses { dPri::Cord, dSec::Cord, dTer::Cord }
|
||||
@ -145,6 +175,7 @@ data Dawn = MkDawn
|
||||
deriveNoun ''Dnses
|
||||
deriveNoun ''EthPoint
|
||||
deriveNoun ''Seed
|
||||
deriveNoun ''Germ
|
||||
deriveNoun ''Dawn
|
||||
|
||||
|
||||
@ -239,6 +270,16 @@ data BoatEv
|
||||
deriveNoun ''BoatEv
|
||||
|
||||
|
||||
-- Jael Events -----------------------------------------------------------------
|
||||
|
||||
data JaelEv
|
||||
= JaelEvRekey () (Life, Ring)
|
||||
| JaelEvCrud Path Noun
|
||||
deriving (Eq, Show)
|
||||
|
||||
deriveNoun ''JaelEv
|
||||
|
||||
|
||||
-- Timer Events ----------------------------------------------------------------
|
||||
|
||||
data BehnEv
|
||||
@ -313,6 +354,7 @@ data BlipEv
|
||||
| BlipEvBoat BoatEv
|
||||
| BlipEvHttpClient HttpClientEv
|
||||
| BlipEvHttpServer HttpServerEv
|
||||
| BlipEvJael JaelEv
|
||||
| BlipEvNewt NewtEv
|
||||
| BlipEvSync SyncEv
|
||||
| BlipEvTerm TermEv
|
||||
@ -335,6 +377,7 @@ instance ToNoun Ev where
|
||||
EvBlip v@BlipEvBoat{} -> reorgThroughNoun ("clay", v)
|
||||
EvBlip v@BlipEvHttpClient{} -> reorgThroughNoun ("iris", v)
|
||||
EvBlip v@BlipEvHttpServer{} -> reorgThroughNoun ("eyre", v)
|
||||
EvBlip v@BlipEvJael{} -> reorgThroughNoun ("jael", v)
|
||||
EvBlip v@BlipEvNewt{} -> reorgThroughNoun ("ames", v)
|
||||
EvBlip v@BlipEvSync{} -> reorgThroughNoun ("clay", v)
|
||||
EvBlip v@BlipEvTerm{} -> reorgThroughNoun ("dill", v)
|
||||
@ -362,6 +405,7 @@ getSpinnerNameForEvent = \case
|
||||
BlipEvBoat _ -> Just "boat"
|
||||
BlipEvHttpClient _ -> Just "iris"
|
||||
BlipEvHttpServer _ -> Just "eyre"
|
||||
BlipEvJael _ -> Just "jael"
|
||||
BlipEvNewt _ -> Just "newt"
|
||||
BlipEvSync _ -> Just "clay"
|
||||
BlipEvTerm t | isRet t -> Nothing
|
||||
|
@ -184,8 +184,9 @@ tryBootFromPill
|
||||
-> Bool
|
||||
-> Ship
|
||||
-> LegacyBootEvent
|
||||
-> Feed
|
||||
-> RIO PierEnv ()
|
||||
tryBootFromPill oExit pill lite ship boot = do
|
||||
tryBootFromPill oExit pill lite ship boot feed = do
|
||||
mStart <- newEmptyMVar
|
||||
vSlog <- logSlogs
|
||||
runOrExitImmediately vSlog (bootedPier vSlog) oExit mStart []
|
||||
@ -193,7 +194,7 @@ tryBootFromPill oExit pill lite ship boot = do
|
||||
bootedPier vSlog = do
|
||||
view pierPathL >>= lockFile
|
||||
rio $ logInfo "Starting boot"
|
||||
sls <- Pier.booted vSlog pill lite ship boot
|
||||
sls <- Pier.booted vSlog pill lite ship boot feed
|
||||
rio $ logInfo "Completed boot"
|
||||
pure sls
|
||||
|
||||
@ -395,7 +396,12 @@ testPill pax showPil showSeq = do
|
||||
pill <- fromNounErr pillNoun & either (throwIO . uncurry ParseErr) pure
|
||||
|
||||
logInfo "Using pill to generate boot sequence."
|
||||
bootSeq <- genBootSeq (Ship 0) pill False (Fake (Ship 0))
|
||||
bootSeq <- genBootSeq
|
||||
(Ship 0)
|
||||
pill
|
||||
False
|
||||
(Fake (Ship 0))
|
||||
(Feed1 $ Germs (Ship 0) [])
|
||||
|
||||
logInfo "Validate jam/cue and toNoun/fromNoun on pill value"
|
||||
reJam <- validateNounVal pill
|
||||
@ -500,12 +506,12 @@ newShip CLI.New{..} opts = do
|
||||
let seed = mineComet (Set.fromList starList) eny
|
||||
putStrLn ("boot: found comet " ++ renderShip (sShip seed))
|
||||
putStrLn ("code: " ++ (tshow $ deriveCode $ sRing seed))
|
||||
bootFromSeed pill seed
|
||||
bootFromFeed pill $ Feed0 seed
|
||||
|
||||
CLI.BootFake name -> do
|
||||
pill <- pillFrom nPillSource
|
||||
ship <- shipFrom name
|
||||
runTryBootFromPill pill name ship (Fake ship)
|
||||
runTryBootFromPill pill name ship (Fake ship) (Feed1 $ Germs ship [])
|
||||
|
||||
CLI.BootFromKeyfile keyFile -> do
|
||||
text <- readFileUtf8 keyFile
|
||||
@ -514,13 +520,13 @@ newShip CLI.New{..} opts = do
|
||||
Just (UW a) -> pure a
|
||||
|
||||
asNoun <- cueExn asAtom
|
||||
seed :: Seed <- case fromNoun asNoun of
|
||||
feed :: Feed <- case fromNoun asNoun of
|
||||
Nothing -> error "Keyfile does not seem to contain a seed."
|
||||
Just s -> pure s
|
||||
|
||||
pill <- pillFrom nPillSource
|
||||
|
||||
bootFromSeed pill seed
|
||||
bootFromFeed pill feed
|
||||
|
||||
where
|
||||
shipFrom :: Text -> RIO HostEnv Ship
|
||||
@ -541,16 +547,16 @@ newShip CLI.New{..} opts = do
|
||||
Nothing -> error "Urbit.ob didn't produce string with ~"
|
||||
Just x -> pure x
|
||||
|
||||
bootFromSeed :: Pill -> Seed -> RIO HostEnv ()
|
||||
bootFromSeed pill seed = do
|
||||
ethReturn <- dawnVent nEthNode seed
|
||||
bootFromFeed :: Pill -> Feed -> RIO HostEnv ()
|
||||
bootFromFeed pill feed = do
|
||||
ethReturn <- dawnVent nEthNode feed
|
||||
|
||||
case ethReturn of
|
||||
Left x -> error $ unpack x
|
||||
Right dawn -> do
|
||||
let ship = sShip $ dSeed dawn
|
||||
name <- nameFromShip ship
|
||||
runTryBootFromPill pill name ship (Dawn dawn)
|
||||
runTryBootFromPill pill name ship (Dawn dawn) feed
|
||||
|
||||
-- Now that we have all the information for running an application with a
|
||||
-- PierConfig, do so.
|
||||
@ -558,13 +564,14 @@ newShip CLI.New{..} opts = do
|
||||
-> Text
|
||||
-> Ship
|
||||
-> LegacyBootEvent
|
||||
-> Feed
|
||||
-> RIO HostEnv ()
|
||||
runTryBootFromPill pill name ship bootEvent = do
|
||||
runTryBootFromPill pill name ship bootEvent feed = do
|
||||
vKill <- view (kingEnvL . kingEnvKillSignal)
|
||||
let pierConfig = toPierConfig (pierPath name) nSerfExe opts
|
||||
let networkConfig = toNetworkConfig opts
|
||||
runPierEnv pierConfig networkConfig vKill $
|
||||
tryBootFromPill True pill nLite ship bootEvent
|
||||
tryBootFromPill True pill nLite ship bootEvent feed
|
||||
|
||||
runShipEnv :: Maybe Text -> CLI.Run -> CLI.Opts -> TMVar () -> RIO PierEnv a
|
||||
-> RIO HostEnv a
|
||||
@ -642,13 +649,13 @@ checkDawn provider keyfilePath = do
|
||||
Just (UW a) -> pure a
|
||||
|
||||
asNoun <- cueExn asAtom
|
||||
seed :: Seed <- case fromNoun asNoun of
|
||||
feed :: Feed <- case fromNoun asNoun of
|
||||
Nothing -> error "Keyfile does not seem to contain a seed."
|
||||
Just s -> pure s
|
||||
|
||||
print $ show seed
|
||||
print $ show feed
|
||||
|
||||
e <- dawnVent provider seed
|
||||
e <- dawnVent provider feed
|
||||
print $ show e
|
||||
|
||||
|
||||
|
@ -335,45 +335,72 @@ retrievePoint endpoint block ship =
|
||||
[x] -> pure x
|
||||
_ -> error "JSON server returned multiple return values."
|
||||
|
||||
validateShipAndGetSponsor :: String -> TextBlockNum -> Seed -> RIO e Ship
|
||||
validateShipAndGetSponsor endpoint block (Seed ship life ring oaf) =
|
||||
case clanFromShip ship of
|
||||
Ob.Comet -> validateComet
|
||||
Ob.Moon -> validateMoon
|
||||
_ -> validateRest
|
||||
validateFeedAndGetSponsor :: String
|
||||
-> TextBlockNum
|
||||
-> Feed
|
||||
-> RIO e (Seed, Ship)
|
||||
validateFeedAndGetSponsor endpoint block = \case
|
||||
Feed0 s -> do
|
||||
r <- validateSeed s
|
||||
case r of
|
||||
Left e -> error e
|
||||
Right r -> pure (s, r)
|
||||
Feed1 s -> validateGerms s
|
||||
|
||||
where
|
||||
validateComet = do
|
||||
-- A comet address is the fingerprint of the keypair
|
||||
let shipFromPass = cometFingerprint $ ringToPass ring
|
||||
when (ship /= shipFromPass) $
|
||||
error ("comet name doesn't match fingerprint " <> show ship <> " vs " <>
|
||||
show shipFromPass)
|
||||
when (life /= 1) $
|
||||
error ("comet can never be re-keyed")
|
||||
pure (shipSein ship)
|
||||
validateGerms Germs{..} =
|
||||
case gFeed of
|
||||
[] -> error "no usable keys in keyfile"
|
||||
(Germ{..}:f) -> do
|
||||
let seed = Seed gShip gLife gRing Nothing
|
||||
r :: Either String Ship
|
||||
<- validateSeed seed
|
||||
case r of
|
||||
Left _ -> validateGerms $ Germs gShip f
|
||||
Right r -> pure (seed, r)
|
||||
|
||||
validateMoon = do
|
||||
-- TODO: The current code in zuse does nothing, but we should be able to
|
||||
-- try to validate the oath against the current as exists planet on
|
||||
-- chain.
|
||||
pure $ shipSein ship
|
||||
validateSeed (Seed ship life ring oaf) = do
|
||||
case clanFromShip ship of
|
||||
Ob.Comet -> pure validateComet
|
||||
Ob.Moon -> pure validateMoon
|
||||
_ -> validateRest
|
||||
where
|
||||
cometFromPass = cometFingerprint $ ringToPass ring
|
||||
validateComet
|
||||
-- A comet address is the fingerprint of the keypair
|
||||
| (ship /= cometFromPass) =
|
||||
Left ("comet name doesn't match fingerprint " <>
|
||||
show ship <> " vs " <>
|
||||
show cometFromPass)
|
||||
| (life /= 1) =
|
||||
Left "comet can never be re-keyed"
|
||||
| otherwise =
|
||||
Right (shipSein ship)
|
||||
|
||||
validateRest = do
|
||||
putStrLn ("boot: retrieving " <> renderShip ship <> "'s public keys")
|
||||
validateMoon =
|
||||
-- TODO: The current code in zuse does nothing, but we should be able
|
||||
-- to try to validate the oath against the current as exists planet
|
||||
-- on chain.
|
||||
Right $ shipSein ship
|
||||
|
||||
whoP <- retrievePoint endpoint block ship
|
||||
case epNet whoP of
|
||||
Nothing -> error "ship not keyed"
|
||||
Just (netLife, pass, contNum, (hasSponsor, who), _) -> do
|
||||
when (netLife /= life) $
|
||||
error ("keyfile life mismatch; keyfile claims life " <>
|
||||
show life <> ", but Azimuth claims life " <>
|
||||
show netLife)
|
||||
when ((ringToPass ring) /= pass) $
|
||||
error "keyfile does not match blockchain"
|
||||
-- TODO: The hoon code does a breach check, but the C code never
|
||||
-- supplies the data necessary for it to function.
|
||||
pure who
|
||||
validateRest = do
|
||||
putStrLn ("boot: retrieving " <> renderShip ship <> "'s public keys")
|
||||
|
||||
--TODO could cache this lookup
|
||||
whoP <- retrievePoint endpoint block ship
|
||||
case epNet whoP of
|
||||
Nothing -> pure $ Left "ship not keyed"
|
||||
Just (netLife, pass, contNum, (hasSponsor, who), _) -> do
|
||||
if (netLife /= life) then
|
||||
pure $ Left ("keyfile life mismatch; keyfile claims life " <>
|
||||
show life <> ", but Azimuth claims life " <>
|
||||
show netLife)
|
||||
else if ((ringToPass ring) /= pass) then
|
||||
pure $ Left "keyfile does not match blockchain"
|
||||
-- TODO: The hoon code does a breach check, but the C code never
|
||||
-- supplies the data necessary for it to function.
|
||||
else
|
||||
pure $ Right who
|
||||
|
||||
|
||||
-- Walk through the sponsorship chain retrieving the actual sponsorship chain
|
||||
@ -402,8 +429,8 @@ getSponsorshipChain endpoint block = loop
|
||||
pure $ chain <> [(ship, ethPoint)]
|
||||
|
||||
-- Produces either an error or a validated boot event structure.
|
||||
dawnVent :: HasLogFunc e => String -> Seed -> RIO e (Either Text Dawn)
|
||||
dawnVent provider dSeed@(Seed ship life ring oaf) =
|
||||
dawnVent :: HasLogFunc e => String -> Feed -> RIO e (Either Text Dawn)
|
||||
dawnVent provider feed =
|
||||
-- The type checker can't figure this out on its own.
|
||||
(onLeft tshow :: Either SomeException Dawn -> Either Text Dawn) <$> try do
|
||||
putStrLn ("boot: requesting ethereum information from " <> pack provider)
|
||||
@ -417,7 +444,8 @@ dawnVent provider dSeed@(Seed ship life ring oaf) =
|
||||
let dBloq = hexStrToAtom hexStrBlock
|
||||
putStrLn ("boot: ethereum block #" <> tshow dBloq)
|
||||
|
||||
immediateSponsor <- validateShipAndGetSponsor provider hexStrBlock dSeed
|
||||
(dSeed, immediateSponsor)
|
||||
<- validateFeedAndGetSponsor provider hexStrBlock feed
|
||||
dSponsor <- getSponsorshipChain provider hexStrBlock immediateSponsor
|
||||
|
||||
putStrLn "boot: retrieving galaxy table"
|
||||
@ -431,7 +459,7 @@ dawnVent provider dSeed@(Seed ship life ring oaf) =
|
||||
|
||||
let dNode = Nothing
|
||||
|
||||
pure $ MkDawn{..}
|
||||
pure MkDawn{..}
|
||||
|
||||
|
||||
-- Comet List ------------------------------------------------------------------
|
||||
|
@ -79,12 +79,17 @@ genEntropy :: MonadIO m => m Entropy
|
||||
genEntropy = Entropy . fromIntegral . bytesAtom <$> io (Ent.getEntropy 64)
|
||||
|
||||
genBootSeq :: HasKingEnv e
|
||||
=> Ship -> Pill -> Bool -> LegacyBootEvent -> RIO e BootSeq
|
||||
genBootSeq _ PillIvory {} _ _ = throwIO CannotBootFromIvoryPill
|
||||
genBootSeq ship PillPill {..} lite boot = do
|
||||
=> Ship -> Pill -> Bool -> LegacyBootEvent -> Feed -> RIO e BootSeq
|
||||
genBootSeq _ PillIvory {} _ _ _ = throwIO CannotBootFromIvoryPill
|
||||
genBootSeq ship PillPill {..} lite boot feed = do
|
||||
ent <- io genEntropy
|
||||
wyr <- wyrd
|
||||
let ova = preKern ent <> [wyr] <> pKernelOva <> postKern <> pUserspaceOva
|
||||
let ova = preKern ent
|
||||
<> [wyr]
|
||||
<> pKernelOva
|
||||
<> postKern
|
||||
<> extraKeys
|
||||
<> pUserspaceOva
|
||||
pure $ BootSeq ident pBootFormulae ova
|
||||
where
|
||||
ident = LogIdentity ship isFake (fromIntegral $ length pBootFormulae)
|
||||
@ -96,6 +101,10 @@ genBootSeq ship PillPill {..} lite boot = do
|
||||
isFake = case boot of
|
||||
Fake _ -> True
|
||||
_ -> False
|
||||
extraKeys = case feed of
|
||||
Feed0 _ -> []
|
||||
Feed1 Germs{..} -> fmap rekey gFeed
|
||||
rekey Germ{..} = EvBlip $ BlipEvJael $ JaelEvRekey () (gLife, gRing)
|
||||
|
||||
|
||||
-- Write to the log. -----------------------------------------------------------
|
||||
@ -160,9 +169,10 @@ booted
|
||||
-> Bool
|
||||
-> Ship
|
||||
-> LegacyBootEvent
|
||||
-> Feed
|
||||
-> RAcquire PierEnv (Serf, EventLog)
|
||||
booted vSlog pill lite ship boot = do
|
||||
rio $ bootNewShip pill lite ship boot
|
||||
booted vSlog pill lite ship boot feed = do
|
||||
rio $ bootNewShip pill lite ship boot feed
|
||||
resumed vSlog Nothing
|
||||
|
||||
bootSeqJobs :: Time.Wen -> BootSeq -> [Job]
|
||||
@ -183,9 +193,10 @@ bootNewShip
|
||||
-> Bool
|
||||
-> Ship
|
||||
-> LegacyBootEvent
|
||||
-> Feed
|
||||
-> RIO e ()
|
||||
bootNewShip pill lite ship bootEv = do
|
||||
seq@(BootSeq ident x y) <- genBootSeq ship pill lite bootEv
|
||||
bootNewShip pill lite ship bootEv feed = do
|
||||
seq@(BootSeq ident x y) <- genBootSeq ship pill lite bootEv feed
|
||||
logInfo "BootSeq Computed"
|
||||
|
||||
pierPath <- view pierPathL
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: urbit-king
|
||||
version: 1.5
|
||||
version: 1.6
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
data-files:
|
||||
|
@ -1,7 +1,7 @@
|
||||
{-|
|
||||
Template Haskell Code to Generate FromNoun and ToNoun Instances
|
||||
-}
|
||||
module Urbit.Noun.TH (deriveNoun, deriveToNoun, deriveFromNoun) where
|
||||
module Urbit.Noun.TH (deriveNoun, deriveToNoun, deriveFromNoun, deriveToNounFunc, deriveFromNounFunc) where
|
||||
|
||||
import ClassyPrelude hiding (fromList)
|
||||
import Control.Monad.Fail (fail)
|
||||
@ -83,13 +83,9 @@ deriveNoun n = (<>) <$> deriveToNoun n <*> deriveFromNoun n
|
||||
|
||||
deriveToNoun :: Name -> Q [Dec]
|
||||
deriveToNoun tyName = do
|
||||
(params, shape) <- typeShape tyName
|
||||
|
||||
let exp = case shape of Vod -> vodToNoun
|
||||
Tup con -> tupToNoun con
|
||||
-- Enu cons -> enumToAtom cons
|
||||
Sum atoms cells -> sumToNoun atoms cells
|
||||
(params, _) <- typeShape tyName
|
||||
|
||||
exp <- deriveToNounFunc tyName
|
||||
params <- pure $ zip ['a' ..] params <&> \(n,_) -> mkName (singleton n)
|
||||
|
||||
let ty = foldl' (\acc v -> AppT acc (VarT v)) (ConT tyName) params
|
||||
@ -101,6 +97,15 @@ deriveToNoun tyName = do
|
||||
|
||||
pure [InstanceD overlap ctx inst [ValD (VarP 'toNoun) body []]]
|
||||
|
||||
deriveToNounFunc :: Name -> Q Exp
|
||||
deriveToNounFunc tyName = do
|
||||
(_, shape) <- typeShape tyName
|
||||
pure case shape of
|
||||
Vod -> vodToNoun
|
||||
Tup con -> tupToNoun con
|
||||
-- Enu cons -> enumToAtom cons
|
||||
Sum atoms cells -> sumToNoun atoms cells
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
addErrTag :: String -> Exp -> Exp
|
||||
@ -111,13 +116,9 @@ addErrTag tag exp =
|
||||
|
||||
deriveFromNoun :: Name -> Q [Dec]
|
||||
deriveFromNoun tyName = do
|
||||
(params, shape) <- typeShape tyName
|
||||
|
||||
let exp = case shape of Vod -> vodFromNoun
|
||||
Tup con -> tupFromNoun con
|
||||
-- Enu cons -> enumFromAtom cons
|
||||
Sum atoms cells -> sumFromNoun atoms cells
|
||||
(params, _) <- typeShape tyName
|
||||
|
||||
exp <- deriveFromNounFunc tyName
|
||||
params <- pure $ zip ['a' ..] params <&> \(n,_) -> mkName (singleton n)
|
||||
|
||||
let ty = foldl' (\acc v -> AppT acc (VarT v)) (ConT tyName) params
|
||||
@ -129,6 +130,15 @@ deriveFromNoun tyName = do
|
||||
|
||||
pure [InstanceD overlap ctx inst [ValD (VarP 'parseNoun) body []]]
|
||||
|
||||
deriveFromNounFunc :: Name -> Q Exp
|
||||
deriveFromNounFunc tyName = do
|
||||
(_, shape) <- typeShape tyName
|
||||
pure case shape of
|
||||
Vod -> vodFromNoun
|
||||
Tup con -> tupFromNoun con
|
||||
-- Enu cons -> enumFromAtom cons
|
||||
Sum atoms cells -> sumFromNoun atoms cells
|
||||
|
||||
sumFromNoun :: [(String, Name)] -> [(String, ConInfo)] -> Exp
|
||||
sumFromNoun [] cl = taggedFromNoun cl
|
||||
sumFromNoun at [] = enumFromAtom at
|
||||
|
90
pkg/interface/src/logic/lib/notificationRedirects.ts
Normal file
90
pkg/interface/src/logic/lib/notificationRedirects.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import useMetadataState from '../state/metadata';
|
||||
import ob from 'urbit-ob';
|
||||
|
||||
function getGroupResourceRedirect(key: string) {
|
||||
const association = useMetadataState.getState().associations.graph[`/ship/${key}`];
|
||||
const { metadata } = association;
|
||||
if(!association || !('graph' in metadata.config)) {
|
||||
return '';
|
||||
}
|
||||
return `/~landscape${association.group}/resource/${metadata.config.graph}${association.resource}`;
|
||||
}
|
||||
|
||||
function getPostRedirect(key: string, segs: string[]) {
|
||||
const association = useMetadataState.getState().associations.graph[`/ship/${key}`];
|
||||
const { metadata } = association;
|
||||
if(!association || !('graph' in metadata.config)) {
|
||||
return '';
|
||||
}
|
||||
return `/~landscape${association.group}/feed/thread/${segs.slice(0, -1).join('/')}`;
|
||||
}
|
||||
|
||||
function getChatRedirect(chat: string, segs: string[]) {
|
||||
const qs = segs.length > 0 ? `?msg=${segs[0]}` : '';
|
||||
return `${getGroupResourceRedirect(chat)}${qs}`;
|
||||
}
|
||||
|
||||
function getPublishRedirect(graphKey: string, segs: string[]) {
|
||||
const base = getGroupResourceRedirect(graphKey);
|
||||
if(segs.length === 3) {
|
||||
return `${base}/note/${segs[0]}`;
|
||||
} else if (segs.length === 4) {
|
||||
return `${base}/note/${segs[0]}?selected=${segs[2]}`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function getLinkRedirect(graphKey: string, segs: string[]) {
|
||||
const base = getGroupResourceRedirect(graphKey);
|
||||
if(segs.length === 1) {
|
||||
return `${base}/index/${segs[0]}`;
|
||||
} else if (segs.length === 3) {
|
||||
return `${base}/index/${segs[0]}?selected=${segs[1]}`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function getGraphRedirect(link: string) {
|
||||
const [,mark, ship, name, ...rest] = link.split('/');
|
||||
const graphKey = `${ship}/${name}`;
|
||||
switch(mark) {
|
||||
case 'graph-validator-dm':
|
||||
return `/~landscape/messages/dm/${ob.patp(rest[0])}`;
|
||||
case 'graph-validator-chat':
|
||||
return getChatRedirect(graphKey, rest);
|
||||
case 'graph-validator-publish':
|
||||
return getPublishRedirect(graphKey, rest);
|
||||
case 'graph-validator-link':
|
||||
return getLinkRedirect(graphKey, rest);
|
||||
case 'graph-validator-post':
|
||||
return getPostRedirect(graphKey, rest);
|
||||
default:
|
||||
return'';
|
||||
}
|
||||
}
|
||||
|
||||
function getInviteRedirect(link: string) {
|
||||
const [,,app,uid] = link.split('/');
|
||||
return `/invites/${app}/${uid}`;
|
||||
}
|
||||
|
||||
function getDmRedirect(link: string) {
|
||||
const [,,ship] = link.split('/');
|
||||
return `/~landscape/messages/dm/${ship}`;
|
||||
}
|
||||
function getGroupRedirect(link: string) {
|
||||
const [,,ship,name] = link.split('/');
|
||||
return `/~landscape/ship/${ship}/${name}`;
|
||||
}
|
||||
|
||||
export function getNotificationRedirect(link: string) {
|
||||
if(link.startsWith('/graph-validator')) {
|
||||
return getGraphRedirect(link);
|
||||
} else if (link.startsWith('/invite')) {
|
||||
return getInviteRedirect(link);
|
||||
} else if (link.startsWith('/dm')) {
|
||||
return getDmRedirect(link);
|
||||
} else if (link.startsWith('/groups')) {
|
||||
return getGroupRedirect(link);
|
||||
}
|
||||
}
|
@ -89,6 +89,7 @@ const otherIndex = function(config) {
|
||||
const idx = {
|
||||
mychannel: result('My Channels', '/~landscape/home', 'home', null),
|
||||
profile: result('Profile', `/~profile/~${window.ship}`, 'profile', null),
|
||||
updates: result('Notifications', '/~notifications', 'notifications', null),
|
||||
messages: result('Messages', '/~landscape/messages', 'messages', null),
|
||||
logout: result('Log Out', '/~/logout', 'logout', null)
|
||||
};
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
HarkPlace,
|
||||
Timebox,
|
||||
HarkStats
|
||||
HarkStats,
|
||||
harkBinToId,
|
||||
makePatDa
|
||||
} from '@urbit/api';
|
||||
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
|
||||
import _ from 'lodash';
|
||||
@ -12,7 +14,7 @@ import { HarkState as State } from '../state/hark';
|
||||
type HarkState = State & BaseState<State>;
|
||||
|
||||
function calculateCount(json: any, state: HarkState) {
|
||||
state.notificationsCount = Object.keys(state.unreadNotes).length;
|
||||
state.notificationsCount = Object.keys(state.unseen).length;
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -170,7 +172,8 @@ function allStats(json: any, state: HarkState): HarkState {
|
||||
function clearState(state: HarkState): HarkState {
|
||||
const initialState = {
|
||||
notifications: new BigIntOrderedMap<Timebox>(),
|
||||
archivedNotifications: new BigIntOrderedMap<Timebox>(),
|
||||
unseen: {},
|
||||
seen: {},
|
||||
notificationsGroupConfig: [],
|
||||
notificationsGraphConfig: {
|
||||
watchOnSelf: false,
|
||||
@ -204,6 +207,87 @@ function more(json: any, state: HarkState): HarkState {
|
||||
return state;
|
||||
}
|
||||
|
||||
function added(json: any, state: HarkState): HarkState {
|
||||
if('added' in json) {
|
||||
const { bin } = json.added;
|
||||
const binId = harkBinToId(bin);
|
||||
state.unseen[binId] = json.added;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function archived(json: any, state: HarkState): HarkState {
|
||||
if('archived' in json) {
|
||||
const { lid, notification } = json.archived;
|
||||
const seen = 'seen' in lid ? 'seen' : 'unseen';
|
||||
const binId = harkBinToId(notification.bin);
|
||||
delete state[seen][binId];
|
||||
const time = makePatDa(json.archived.time);
|
||||
const timebox = state.archive?.get(time) || {};
|
||||
timebox[binId] = notification;
|
||||
state.archive = state.archive.set(time, timebox);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function timebox(json: any, state: HarkState): HarkState {
|
||||
if('timebox' in json) {
|
||||
const { timebox } = json;
|
||||
const { lid, notifications } = timebox;
|
||||
if('archive' in lid) {
|
||||
const time = makePatDa(lid.archive);
|
||||
const old = state.archive.get(time) || {};
|
||||
notifications.forEach((note: any) => {
|
||||
const binId = harkBinToId(note.bin);
|
||||
old[binId] = note;
|
||||
});
|
||||
state.archive = state.archive.set(time, old);
|
||||
} else {
|
||||
const seen = 'seen' in lid ? 'seen' : 'unseen';
|
||||
notifications.forEach((note: any) => {
|
||||
const binId = harkBinToId(note.bin);
|
||||
state[seen][binId] = note;
|
||||
});
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function opened(json: any, state: HarkState): HarkState {
|
||||
if('opened' in json) {
|
||||
const bins = Object.keys(state.unseen);
|
||||
bins.forEach((bin) => {
|
||||
const old = state.seen[bin];
|
||||
const curr = state.unseen[bin];
|
||||
curr.body = [...curr.body, ...(old?.body || [])];
|
||||
state.seen[bin] = curr;
|
||||
delete state.unseen[bin];
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function delPlace(json: any, state: HarkState): HarkState {
|
||||
if('del-place' in json) {
|
||||
const { path, desk } = json['del-place'];
|
||||
const pathId = `${desk}${path}`;
|
||||
const wipeBox = (t: Timebox) => {
|
||||
Object.keys(t).forEach((bin) => {
|
||||
if (bin.startsWith(pathId)) {
|
||||
delete t[bin];
|
||||
}
|
||||
});
|
||||
};
|
||||
wipeBox(state.unseen);
|
||||
wipeBox(state.seen);
|
||||
state.archive.keys().forEach((key) => {
|
||||
wipeBox(state.archive.get(key)!);
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export function reduce(data, state) {
|
||||
const reducers = [
|
||||
calculateCount,
|
||||
@ -215,7 +299,12 @@ export function reduce(data, state) {
|
||||
unreadSince,
|
||||
unreadEach,
|
||||
seenIndex,
|
||||
readAll
|
||||
readAll,
|
||||
added,
|
||||
timebox,
|
||||
archived,
|
||||
opened,
|
||||
delPlace
|
||||
];
|
||||
const reducer = compose(reducers.map(r => (s) => {
|
||||
return r(data, s);
|
||||
|
@ -2,9 +2,14 @@ import {
|
||||
archive,
|
||||
HarkBin,
|
||||
markCountAsRead,
|
||||
Notification,
|
||||
NotificationGraphConfig,
|
||||
Unreads
|
||||
Unreads,
|
||||
Timebox,
|
||||
HarkLid,
|
||||
harkBinToId,
|
||||
decToUd,
|
||||
unixToDa,
|
||||
opened
|
||||
} from '@urbit/api';
|
||||
import { Poke } from '@urbit/http-api';
|
||||
import { patp2dec } from 'urbit-ob';
|
||||
@ -17,40 +22,32 @@ import {
|
||||
createState,
|
||||
createSubscription,
|
||||
pokeOptimisticallyN,
|
||||
reduceState,
|
||||
reduceStateN
|
||||
} from './base';
|
||||
import { reduce, reduceGraph, reduceGroup } from '../reducers/hark-update';
|
||||
import { BigInteger } from 'big-integer';
|
||||
|
||||
export const HARK_FETCH_MORE_COUNT = 3;
|
||||
|
||||
export interface HarkState {
|
||||
archivedNotifications: BigIntOrderedMap<Notification[]>;
|
||||
archive: BigIntOrderedMap<Timebox>;
|
||||
doNotDisturb: boolean;
|
||||
poke: (poke: Poke<any>) => Promise<void>;
|
||||
getMore: () => Promise<boolean>;
|
||||
getSubset: (
|
||||
offset: number,
|
||||
count: number,
|
||||
isArchive: boolean
|
||||
) => Promise<void>;
|
||||
opened: () => void;
|
||||
// getTimeSubset: (start?: Date, end?: Date) => Promise<void>;
|
||||
notifications: BigIntOrderedMap<Notification[]>;
|
||||
unreadNotes: Notification[];
|
||||
unseen: Timebox;
|
||||
seen: Timebox;
|
||||
notificationsCount: number;
|
||||
notificationsGraphConfig: NotificationGraphConfig; // TODO unthread this everywhere
|
||||
notificationsGroupConfig: string[];
|
||||
unreads: Unreads;
|
||||
archive: (bin: HarkBin, time?: BigInteger) => Promise<void>;
|
||||
readNote: (bin: HarkBin) => Promise<void>;
|
||||
readCount: (path: string) => Promise<void>;
|
||||
archiveNote: (bin: HarkBin, lid: HarkLid) => Promise<void>;
|
||||
}
|
||||
|
||||
const useHarkState = createState<HarkState>(
|
||||
'Hark',
|
||||
(set, get) => ({
|
||||
archivedNotifications: new BigIntOrderedMap<Notification[]>(),
|
||||
archive: new BigIntOrderedMap<Timebox>(),
|
||||
doNotDisturb: false,
|
||||
unreadNotes: [],
|
||||
poke: async (poke: Poke<any>) => {
|
||||
@ -60,29 +57,36 @@ const useHarkState = createState<HarkState>(
|
||||
const poke = markCountAsRead({ desk: (window as any).desk, path });
|
||||
await pokeOptimisticallyN(useHarkState, poke, [reduce]);
|
||||
},
|
||||
archive: async (bin: HarkBin, time?: BigInteger) => {
|
||||
const poke = archive(bin, time);
|
||||
await pokeOptimisticallyN(useHarkState, poke, [reduce]);
|
||||
opened: async () => {
|
||||
reduceStateN(get(), { opened: null }, [reduce]);
|
||||
|
||||
await api.poke(opened);
|
||||
},
|
||||
readNote: async (bin) => {
|
||||
await pokeOptimisticallyN(useHarkState, readNote(bin), [reduce]);
|
||||
archiveNote: async (bin: HarkBin, lid: HarkLid) => {
|
||||
const poke = archive(bin, lid);
|
||||
get().set((draft) => {
|
||||
const key = 'seen' in lid ? 'seen' : 'unseen';
|
||||
const binId = harkBinToId(bin);
|
||||
delete draft[key][binId];
|
||||
});
|
||||
await api.poke(poke);
|
||||
},
|
||||
getMore: async (): Promise<boolean> => {
|
||||
const state = get();
|
||||
const offset = state.notifications.size || 0;
|
||||
await state.getSubset(offset, HARK_FETCH_MORE_COUNT, false);
|
||||
const newState = get();
|
||||
return offset === (newState?.notifications?.size || 0);
|
||||
},
|
||||
getSubset: async (offset, count, isArchive): Promise<void> => {
|
||||
const where = isArchive ? 'archive' : 'inbox';
|
||||
const { harkUpdate } = await api.scry({
|
||||
const oldSize = state.archive?.size || 0;
|
||||
const offset = decToUd(
|
||||
state.archive?.peekSmallest()?.[0].toString()
|
||||
|| unixToDa(Date.now() * 1000).toString()
|
||||
);
|
||||
const update = await api.scry({
|
||||
app: 'hark-store',
|
||||
path: `/recent/${where}/${offset}/${count}`
|
||||
path: `/recent/inbox/${offset}/5`
|
||||
});
|
||||
reduceState(useHarkState, harkUpdate, [reduce]);
|
||||
reduceStateN(useHarkState.getState(), update, [reduce]);
|
||||
return get().archive?.size === oldSize;
|
||||
},
|
||||
notifications: new BigIntOrderedMap<Notification[]>(),
|
||||
unseen: {},
|
||||
seen: {},
|
||||
notificationsCount: 0,
|
||||
notificationsGraphConfig: {
|
||||
watchOnSelf: false,
|
||||
@ -93,9 +97,9 @@ const useHarkState = createState<HarkState>(
|
||||
unreads: {}
|
||||
}),
|
||||
[
|
||||
'unreadNotes',
|
||||
'notifications',
|
||||
'archivedNotifications',
|
||||
'seen',
|
||||
'unseen',
|
||||
'archive',
|
||||
'unreads',
|
||||
'notificationsCount'
|
||||
],
|
||||
|
31
pkg/interface/src/views/apps/notifications/Archive.tsx
Normal file
31
pkg/interface/src/views/apps/notifications/Archive.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import React, { useEffect } from 'react';
|
||||
import useHarkState, { HarkState } from '~/logic/state/hark';
|
||||
import { Notification } from './notification';
|
||||
|
||||
const selArchive = (s: HarkState) => s.archive;
|
||||
|
||||
export function Archive() {
|
||||
const archive = useHarkState(selArchive);
|
||||
const keys = archive.keys();
|
||||
|
||||
useEffect(() => {
|
||||
useHarkState.getState().getMore();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box pt="2" overflowY="auto" overflowX="hidden">
|
||||
{keys.map(key =>
|
||||
Object.entries(archive.get(key)!)
|
||||
.sort(([, a], [, b]) => b.time - a.time)
|
||||
.map(([binId, n]) => (
|
||||
<Notification
|
||||
key={`${key.toString()}-${binId}`}
|
||||
lid={{ time: key.toString() }}
|
||||
notification={n}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
58
pkg/interface/src/views/apps/notifications/NewBox.tsx
Normal file
58
pkg/interface/src/views/apps/notifications/NewBox.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { Box, Center, Col, Text } from '@tlon/indigo-react';
|
||||
import React from 'react';
|
||||
import useHarkState, { HarkState } from '~/logic/state/hark';
|
||||
import { harkBinToId, HarkLid, Timebox } from '../../../../../npm/api/dist';
|
||||
import { Notification } from './notification';
|
||||
|
||||
const unseenLid = { unseen: null };
|
||||
const seenLid = { seen: null };
|
||||
const selUnseen = (s: HarkState) => s.unseen;
|
||||
const selSeen = (s: HarkState) => s.seen;
|
||||
export function NewBox() {
|
||||
const seen = useHarkState(selSeen);
|
||||
const unseen = useHarkState(selUnseen);
|
||||
const empty = Object.keys(seen).length + Object.keys(unseen).length === 0;
|
||||
|
||||
return (
|
||||
<Box pt="2" overflowY="auto" overflowX="hidden">
|
||||
{empty ? (
|
||||
<Center p="3">
|
||||
<Text>All clear!</Text>
|
||||
</Center>
|
||||
) : (
|
||||
<>
|
||||
<Lid lid={unseenLid} timebox={unseen} title="Unseen" />
|
||||
<Lid lid={seenLid} timebox={seen} title="Seen" />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function Lid({
|
||||
lid,
|
||||
timebox,
|
||||
title
|
||||
}: {
|
||||
lid: HarkLid;
|
||||
timebox: Timebox;
|
||||
title: string;
|
||||
}) {
|
||||
if(Object.keys(timebox).length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Text gray p="2">
|
||||
{title}
|
||||
</Text>
|
||||
<Col>
|
||||
{Object.entries(timebox)
|
||||
.sort(([, a], [, b]) => b.time - a.time)
|
||||
.map(([binId, n]) => (
|
||||
<Notification key={harkBinToId(n.bin)} lid={lid} notification={n} />
|
||||
))}
|
||||
</Col>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import {
|
||||
IndexedNotification,
|
||||
JoinRequests,
|
||||
Notifications,
|
||||
seen,
|
||||
Timebox,
|
||||
unixToDa
|
||||
} from '@urbit/api';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import _ from 'lodash';
|
||||
import f from 'lodash/fp';
|
||||
import moment from 'moment';
|
||||
import React, { useEffect } from 'react';
|
||||
import { getNotificationKey } from '~/logic/lib/hark';
|
||||
import { daToUnix } from '~/logic/lib/util';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import { Invites } from './invites';
|
||||
import { Notification } from './notification';
|
||||
import airlock from '~/logic/api';
|
||||
|
||||
type DatedTimebox = [BigInteger, Timebox];
|
||||
|
||||
function filterNotification(groups: string[]) {
|
||||
if (groups.length === 0) {
|
||||
return () => true;
|
||||
}
|
||||
return (n: IndexedNotification) => {
|
||||
if ('graph' in n.index) {
|
||||
const { group } = n.index.graph;
|
||||
return groups.findIndex(g => group === g) !== -1;
|
||||
} else if ('group' in n.index) {
|
||||
const { group } = n.index.group;
|
||||
return groups.findIndex(g => group === g) !== -1;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
export default function Inbox(props: {
|
||||
archive: Notifications;
|
||||
showArchive?: boolean;
|
||||
filter: string[];
|
||||
pendingJoin: JoinRequests;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
let hasSeen = false;
|
||||
setTimeout(() => {
|
||||
hasSeen = true;
|
||||
}, 3000);
|
||||
return () => {
|
||||
if (hasSeen) {
|
||||
airlock.poke(seen());
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const ready = useHarkState(
|
||||
s => Object.keys(s.unreads.graph).length > 0
|
||||
);
|
||||
|
||||
const getMore = useHarkState(s => s.getMore);
|
||||
|
||||
const notificationState = useHarkState(state => state.notifications);
|
||||
const unreadNotes = useHarkState(s => s.unreadNotes);
|
||||
const archivedNotifications = useHarkState(state => state.archivedNotifications);
|
||||
|
||||
const notifications =
|
||||
Array.from(props.showArchive ? archivedNotifications : notificationState) || [];
|
||||
|
||||
const notificationsByDay = f.flow(
|
||||
f.map<DatedTimebox, DatedTimebox>(([date, nots]) => [
|
||||
date,
|
||||
nots.filter(filterNotification(props.filter))
|
||||
]),
|
||||
f.groupBy<DatedTimebox>(([d]) => {
|
||||
const date = moment(daToUnix(d));
|
||||
if (moment().subtract(6, 'hours').isBefore(date)) {
|
||||
return 'latest';
|
||||
} else {
|
||||
return date.format('YYYYMMDD');
|
||||
}
|
||||
})
|
||||
)(notifications);
|
||||
|
||||
const notificationsByDayMap = new Map<string, DatedTimebox[]>(
|
||||
Object.keys(notificationsByDay).map((timebox) => {
|
||||
return [timebox, notificationsByDay[timebox]];
|
||||
})
|
||||
);
|
||||
|
||||
const date = unixToDa(Date.now());
|
||||
|
||||
return (
|
||||
<Col p={1} position="relative" height="100%" overflowY="auto" overflowX="hidden">
|
||||
<Invites pendingJoin={props.pendingJoin} />
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
||||
function sortTimeboxes([a]: DatedTimebox, [b]: DatedTimebox) {
|
||||
return b.subtract(a);
|
||||
}
|
||||
|
||||
function sortIndexedNotification(
|
||||
{ notification: a }: IndexedNotification,
|
||||
{ notification: b }: IndexedNotification
|
||||
) {
|
||||
return b.time - a.time;
|
||||
}
|
||||
|
||||
function DaySection({
|
||||
timeboxes,
|
||||
unread = false
|
||||
}) {
|
||||
const lent = timeboxes.map(([,nots]) => nots.length).reduce(f.add, 0);
|
||||
if (lent === 0 || timeboxes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{_.map(timeboxes.sort(sortTimeboxes), ([date, nots], i: number) =>
|
||||
_.map(nots.sort(sortIndexedNotification), (not, j: number) => (
|
||||
<Notification
|
||||
key={getNotificationKey(date, not)}
|
||||
notification={not}
|
||||
unread={unread}
|
||||
time={!unread ? date : undefined}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,64 +1,112 @@
|
||||
import { Box, Button, Icon, Row } from '@tlon/indigo-react';
|
||||
import { Box, Col, Text, Button, Icon, Row } from '@tlon/indigo-react';
|
||||
import {
|
||||
GraphNotificationContents,
|
||||
GroupNotificationContents,
|
||||
IndexedNotification
|
||||
HarkLid,
|
||||
harkLidToId,
|
||||
harkBinToId,
|
||||
Notification as INotification,
|
||||
HarkContent
|
||||
} from '@urbit/api';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import React, { ReactNode, useCallback } from 'react';
|
||||
import { getNotificationKey } from '~/logic/lib/hark';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useHovering } from '~/logic/lib/util';
|
||||
import useLocalState from '~/logic/state/local';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import { SwipeMenu } from '~/views/components/SwipeMenu';
|
||||
import { GraphNotification } from './graph';
|
||||
import { GroupNotification } from './group';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import shallow from 'zustand/shallow';
|
||||
import { map, take, uniqBy } from 'lodash';
|
||||
import { Mention } from '~/views/components/MentionText';
|
||||
import { PropFunc } from '~/types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { getNotificationRedirect } from '~/logic/lib/notificationRedirects';
|
||||
|
||||
export interface NotificationProps {
|
||||
notification: IndexedNotification;
|
||||
notification: INotification;
|
||||
time: BigInteger;
|
||||
unread: boolean;
|
||||
}
|
||||
|
||||
export function NotificationWrapper(props: {
|
||||
time?: BigInteger;
|
||||
read?: boolean;
|
||||
notification?: IndexedNotification;
|
||||
children: ReactNode;
|
||||
const MAX_CONTENTS = 5;
|
||||
|
||||
interface NotificationTextProps extends PropFunc<typeof Box> {
|
||||
contents: HarkContent[];
|
||||
}
|
||||
const NotificationText = ({ contents, ...rest }: NotificationTextProps) => {
|
||||
return (
|
||||
<>
|
||||
{contents.map((content, idx) => {
|
||||
if ('ship' in content) {
|
||||
return (
|
||||
<Mention
|
||||
key={idx}
|
||||
ship={content.ship}
|
||||
first={idx === 0}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Text key={idx} {...rest}>{content.text}</Text>;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export function Notification(props: {
|
||||
lid: HarkLid;
|
||||
notification: INotification;
|
||||
}) {
|
||||
const { time, notification, children, read = false } = props;
|
||||
const { notification, lid } = props;
|
||||
const read = !('unseen' in lid);
|
||||
const key = `${harkLidToId(lid)}-${harkBinToId(notification.bin)}`;
|
||||
const history = useHistory();
|
||||
|
||||
const isMobile = useLocalState(s => s.mobile);
|
||||
|
||||
const [archive, readNote] = useHarkState(s => [s.archive, s.readNote], shallow);
|
||||
|
||||
const onArchive = useCallback(async (e) => {
|
||||
e.stopPropagation();
|
||||
if (!notification) {
|
||||
return;
|
||||
}
|
||||
await archive(notification.index, time);
|
||||
}, [time, notification]);
|
||||
|
||||
const onClick = (e: any) => {
|
||||
if (!notification || read) {
|
||||
return;
|
||||
}
|
||||
return readNote(notification.index);
|
||||
};
|
||||
const onArchive = useCallback(
|
||||
async (e) => {
|
||||
e.stopPropagation();
|
||||
if (!notification) {
|
||||
return;
|
||||
}
|
||||
useHarkState.getState().archiveNote(notification.bin, lid);
|
||||
},
|
||||
[notification, lid]
|
||||
);
|
||||
|
||||
const { hovering, bind } = useHovering();
|
||||
const dedupedBody = uniqBy(notification.body, item => item.link);
|
||||
const contents = map(dedupedBody, 'content').filter(
|
||||
c => c.length > 0
|
||||
);
|
||||
const first = notification.body[0];
|
||||
if (!first) {
|
||||
// should be unreachable
|
||||
return null;
|
||||
}
|
||||
|
||||
const onClick = (e: any) => {
|
||||
const redirect = getNotificationRedirect(first.link);
|
||||
if(redirect) {
|
||||
history.push(redirect);
|
||||
} else {
|
||||
console.log('no redirect');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SwipeMenu
|
||||
key={(time && notification && getNotificationKey(time, notification)) ?? 'unknown'}
|
||||
key={key}
|
||||
m={2}
|
||||
menuWidth={100}
|
||||
disabled={!isMobile}
|
||||
menu={
|
||||
<Button onClick={onArchive} ml={2} height="100%" width="92px" primary destructive>
|
||||
<Button
|
||||
onClick={onArchive}
|
||||
ml={2}
|
||||
height="100%"
|
||||
width="92px"
|
||||
primary
|
||||
destructive
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
}
|
||||
@ -71,10 +119,27 @@ export function NotificationWrapper(props: {
|
||||
gridTemplateColumns={['1fr 24px', '1fr 200px']}
|
||||
gridTemplateRows="auto"
|
||||
gridTemplateAreas="'header actions' 'main main'"
|
||||
p={2}
|
||||
p={3}
|
||||
{...bind}
|
||||
>
|
||||
{children}
|
||||
<Col gapY={contents.length === 0 ? 0 : 2}>
|
||||
<Row>
|
||||
<NotificationText contents={first.title} fontWeight="medium" />
|
||||
</Row>
|
||||
<Col gapY="2">
|
||||
{take(contents, MAX_CONTENTS).map((content, i) => (
|
||||
<Box key={i}>
|
||||
<NotificationText lineHeight="tall" contents={content} />
|
||||
</Box>
|
||||
))}
|
||||
</Col>
|
||||
{contents.length > MAX_CONTENTS ? (
|
||||
<Text mt="2" gray display="block">
|
||||
and {contents.length - MAX_CONTENTS} more
|
||||
</Text>
|
||||
) : null}
|
||||
</Col>
|
||||
|
||||
<Row
|
||||
alignItems="flex-start"
|
||||
gapX={2}
|
||||
@ -82,7 +147,7 @@ export function NotificationWrapper(props: {
|
||||
justifyContent="flex-end"
|
||||
opacity={[0, hovering ? 1 : 0]}
|
||||
>
|
||||
{notification && (
|
||||
{!('time' in lid) && (
|
||||
<StatelessAsyncAction
|
||||
name=""
|
||||
borderRadius={1}
|
||||
@ -97,46 +162,3 @@ export function NotificationWrapper(props: {
|
||||
</SwipeMenu>
|
||||
);
|
||||
}
|
||||
|
||||
export function Notification(props: NotificationProps) {
|
||||
const { notification, unread } = props;
|
||||
const { contents, time } = notification.notification;
|
||||
|
||||
const wrapperProps = {
|
||||
notification,
|
||||
read: !unread,
|
||||
time: props.time
|
||||
};
|
||||
|
||||
if ('graph' in notification.index) {
|
||||
const index = notification.index.graph;
|
||||
const c: GraphNotificationContents = (contents as any).graph;
|
||||
|
||||
return (
|
||||
<NotificationWrapper {...wrapperProps}>
|
||||
<GraphNotification
|
||||
index={index}
|
||||
contents={c}
|
||||
read={!unread}
|
||||
timebox={props.time}
|
||||
time={time}
|
||||
/>
|
||||
</NotificationWrapper>
|
||||
);
|
||||
}
|
||||
if ('group' in notification.index) {
|
||||
const index = notification.index.group;
|
||||
const c: GroupNotificationContents = (contents as any).group;
|
||||
return (
|
||||
<NotificationWrapper {...wrapperProps}>
|
||||
<GroupNotification
|
||||
index={index}
|
||||
contents={c}
|
||||
time={time}
|
||||
/>
|
||||
</NotificationWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -1,29 +1,65 @@
|
||||
import { Box, Col, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import React, { ReactElement, useCallback, useRef } from 'react';
|
||||
import { Action, Box, Col, Icon, Row, Text } from '@tlon/indigo-react';
|
||||
import React, { ReactElement, ReactNode, useEffect, useRef } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Link, Route, Switch } from 'react-router-dom';
|
||||
import useGroupState from '~/logic/state/group';
|
||||
import { Link, Route, Switch, useHistory, useLocation } from 'react-router-dom';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import { Body } from '~/views/components/Body';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import { useTutorialModal } from '~/views/components/useTutorialModal';
|
||||
import Inbox from './inbox';
|
||||
import airlock from '~/logic/api';
|
||||
import { readAll } from '@urbit/api';
|
||||
import { Archive } from './Archive';
|
||||
import { NewBox } from './NewBox';
|
||||
|
||||
const baseUrl = '/~notifications';
|
||||
|
||||
export function NavLink({
|
||||
href,
|
||||
children
|
||||
}: {
|
||||
href: string;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const location = useLocation();
|
||||
const { push } = useHistory();
|
||||
|
||||
const isActive = href === location.pathname;
|
||||
|
||||
const onClick = () => {
|
||||
push(href);
|
||||
};
|
||||
|
||||
return (
|
||||
<Action
|
||||
backgroundColor="transparent"
|
||||
onClick={onClick}
|
||||
color={isActive ? 'black' : 'gray'}
|
||||
>
|
||||
{children}
|
||||
</Action>
|
||||
);
|
||||
}
|
||||
|
||||
export default function NotificationsScreen(props: any): ReactElement {
|
||||
const relativePath = (p: string) => baseUrl + p;
|
||||
|
||||
const pendingJoin = useGroupState(s => s.pendingJoin);
|
||||
const onReadAll = useCallback(async () => {
|
||||
await airlock.poke(readAll());
|
||||
}, []);
|
||||
|
||||
const anchorRef = useRef<HTMLElement | null>(null);
|
||||
useTutorialModal('notifications', true, anchorRef);
|
||||
const notificationsCount = useHarkState(state => state.notificationsCount);
|
||||
const onReadAll = async () => {};
|
||||
|
||||
useEffect(() => {
|
||||
function visibilitychange() {
|
||||
if (document.visibilityState === 'hidden') {
|
||||
useHarkState.getState().opened();
|
||||
}
|
||||
}
|
||||
document.addEventListener('visibilitychange', visibilitychange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', visibilitychange);
|
||||
useHarkState.getState().opened();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
@ -33,7 +69,10 @@ export default function NotificationsScreen(props: any): ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
<title>{ notificationsCount ? `(${String(notificationsCount) }) `: '' }Landscape - Notifications</title>
|
||||
<title>
|
||||
{notificationsCount ? `(${String(notificationsCount)}) ` : ''}
|
||||
Groups - Notifications
|
||||
</title>
|
||||
</Helmet>
|
||||
<Body>
|
||||
<Col overflowY="hidden" height="100%">
|
||||
@ -46,22 +85,29 @@ export default function NotificationsScreen(props: any): ReactElement {
|
||||
borderBottom={1}
|
||||
borderBottomColor="lightGray"
|
||||
>
|
||||
|
||||
<Text fontWeight="bold" fontSize={2} lineHeight={1} ref={anchorRef}>
|
||||
Notifications
|
||||
</Text>
|
||||
<Row
|
||||
justifyContent="space-between"
|
||||
gapX={3}
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize={2}
|
||||
lineHeight={1}
|
||||
ref={anchorRef}
|
||||
>
|
||||
<StatelessAsyncAction
|
||||
overflow="hidden"
|
||||
color="black"
|
||||
backgroundColor="white"
|
||||
onClick={onReadAll}
|
||||
>
|
||||
Mark All Read
|
||||
</StatelessAsyncAction>
|
||||
Notifications
|
||||
</Text>
|
||||
<Row gapX="2">
|
||||
<NavLink href="/~notifications">New</NavLink>
|
||||
<NavLink href="/~notifications/archive">Archive</NavLink>
|
||||
</Row>
|
||||
<Row justifyContent="space-between" gapX={3}>
|
||||
{ (false as boolean) ? (
|
||||
<StatelessAsyncAction
|
||||
overflow="hidden"
|
||||
color="black"
|
||||
backgroundColor="white"
|
||||
onClick={onReadAll}
|
||||
>
|
||||
Mark All Read
|
||||
</StatelessAsyncAction>
|
||||
) : null}
|
||||
<Link to="/~settings#notifications">
|
||||
<Box>
|
||||
<Icon lineHeight={1} icon="Adjust" />
|
||||
@ -69,11 +115,9 @@ export default function NotificationsScreen(props: any): ReactElement {
|
||||
</Link>
|
||||
</Row>
|
||||
</Row>
|
||||
{!view && <Inbox
|
||||
pendingJoin={pendingJoin}
|
||||
{...props}
|
||||
filter={[]}
|
||||
/>}
|
||||
{ view === 'archive' ? (
|
||||
<Archive />
|
||||
) : <NewBox /> }
|
||||
</Col>
|
||||
</Body>
|
||||
</>
|
||||
|
@ -20,6 +20,7 @@ import ReconnectButton from './ReconnectButton';
|
||||
import { StatusBarItem } from './StatusBarItem';
|
||||
import { useTutorialModal } from './useTutorialModal';
|
||||
import { StatusBarJoins } from './StatusBarJoins';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
|
||||
const localSel = selectLocalState(['toggleOmnibox']);
|
||||
|
||||
@ -29,6 +30,7 @@ const StatusBar = (props) => {
|
||||
const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+';
|
||||
const { toggleOmnibox } = useLocalState(localSel);
|
||||
const { hideAvatars } = useSettingsState(selectCalmState);
|
||||
const notificationsCount = useHarkState(s => s.notificationsCount);
|
||||
|
||||
const color = ourContact ? `#${uxToHex(ourContact.color)}` : '#000';
|
||||
const xPadding = !hideAvatars && ourContact?.avatar ? '0' : '2';
|
||||
@ -75,7 +77,7 @@ const StatusBar = (props) => {
|
||||
>
|
||||
<Icon icon='Dashboard' color='black' />
|
||||
</Button>
|
||||
<StatusBarItem float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
|
||||
<StatusBarItem position="relative" float={floatLeap} mr={2} onClick={() => toggleOmnibox()}>
|
||||
<Icon icon='LeapArrow' />
|
||||
<Text ref={anchorRef} ml={2} color='black'>
|
||||
Leap
|
||||
@ -83,6 +85,11 @@ const StatusBar = (props) => {
|
||||
<Text display={['none', 'inline']} ml={2} color='gray'>
|
||||
{metaKey}/
|
||||
</Text>
|
||||
{ notificationsCount > 0 && (
|
||||
<Box position="absolute" right="-8px" top="-8px">
|
||||
<Icon icon="Bullet" color="blue" />
|
||||
</Box>
|
||||
)}
|
||||
</StatusBarItem>
|
||||
<StatusBarJoins />
|
||||
<ReconnectButton />
|
||||
|
@ -55,7 +55,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
||||
const [query, setQuery] = useState('');
|
||||
const [selected, setSelected] = useState<[] | [string, string]>([]);
|
||||
const contactState = useContactState(state => state.contacts);
|
||||
const notifications = useHarkState(state => state.notifications);
|
||||
const notificationCount = useHarkState(state => state.notificationsCount);
|
||||
const invites = useInviteState(state => state.invites);
|
||||
const tiles = useLaunchState(state => state.tiles);
|
||||
const [leapCursor, setLeapCursor] = useState('pointer');
|
||||
@ -119,7 +119,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
||||
if (category === 'other') {
|
||||
return [
|
||||
'other',
|
||||
index.get('other').filter(({ app }) => app !== 'tutorial' && app !== 'inbox')
|
||||
index.get('other').filter(({ app }) => app !== 'tutorial')
|
||||
];
|
||||
}
|
||||
return [category, []];
|
||||
@ -163,7 +163,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
||||
app === 'Links' ||
|
||||
app === 'Terminal' ||
|
||||
app === 'home' ||
|
||||
app === 'inbox'
|
||||
app === 'notifications'
|
||||
) {
|
||||
if(shift && app === 'profile') {
|
||||
// TODO: hacky, fix
|
||||
@ -351,6 +351,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
||||
navigate={() => navigate(result.app, result.link, false)}
|
||||
setSelection={() => setSelection(result.app, result.link)}
|
||||
selected={sel}
|
||||
hasNotifications={notificationCount !== 0}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
@ -358,7 +359,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
||||
})}
|
||||
</Box>
|
||||
);
|
||||
}, [results, navigate, selected, contactState, notifications, invites]);
|
||||
}, [results, navigate, selected, contactState, invites]);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
|
@ -39,6 +39,7 @@ interface OmniboxResultProps {
|
||||
shiftLink?: string;
|
||||
shiftDescription?: string;
|
||||
description?: string;
|
||||
hasNotifications?: boolean;
|
||||
}
|
||||
|
||||
interface OmniboxResultState {
|
||||
@ -142,14 +143,20 @@ export class OmniboxResult extends Component<OmniboxResultProps, OmniboxResultSt
|
||||
);
|
||||
} else if (icon === 'notifications') {
|
||||
graphic = (
|
||||
<Box mr="2" height="18px" width="18px" position="relative" display="inline-block">
|
||||
<Icon
|
||||
display='inline-block'
|
||||
verticalAlign='middle'
|
||||
icon='Notifications'
|
||||
mr={2}
|
||||
size='18px'
|
||||
color={iconFill}
|
||||
/>
|
||||
{this.props.hasNotifications ? (
|
||||
<Box position="absolute" right="-6px" top="-4px">
|
||||
<Icon icon="Bullet" color={(this.state.hovered || selected === link) ? 'white' : 'blue'} />
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
);
|
||||
} else if (icon === 'messages') {
|
||||
graphic = (
|
||||
|
@ -2,7 +2,6 @@ import { Box } from '@tlon/indigo-react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { Route, Switch, useHistory, useLocation } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import ob from 'urbit-ob';
|
||||
import { useLocalStorageState } from '~/logic/lib/useLocalStorageState';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import LaunchApp from '~/views/apps/launch/App';
|
||||
@ -15,6 +14,7 @@ import { useShortcut } from '~/logic/state/settings';
|
||||
|
||||
import Landscape from '~/views/landscape/index';
|
||||
import GraphApp from '../../apps/graph/App';
|
||||
import { getNotificationRedirect } from '~/logic/lib/notificationRedirects';
|
||||
|
||||
export const Container = styled(Box)`
|
||||
flex-grow: 1;
|
||||
@ -23,94 +23,6 @@ export const Container = styled(Box)`
|
||||
height: calc(100% - 62px);
|
||||
`;
|
||||
|
||||
function getGroupResourceRedirect(key: string) {
|
||||
const association = useMetadataState.getState().associations.graph[`/ship/${key}`];
|
||||
const { metadata } = association;
|
||||
if(!association || !('graph' in metadata.config)) {
|
||||
return '';
|
||||
}
|
||||
return `/~landscape${association.group}/resource/${metadata.config.graph}${association.resource}`;
|
||||
}
|
||||
|
||||
function getPostRedirect(key: string, segs: string[]) {
|
||||
const association = useMetadataState.getState().associations.graph[`/ship/${key}`];
|
||||
const { metadata } = association;
|
||||
if(!association || !('graph' in metadata.config)) {
|
||||
return '';
|
||||
}
|
||||
return `/~landscape${association.group}/feed/thread/${segs.slice(0, -1).join('/')}`;
|
||||
}
|
||||
|
||||
function getChatRedirect(chat: string, segs: string[]) {
|
||||
const qs = segs.length > 0 ? `?msg=${segs[0]}` : '';
|
||||
return `${getGroupResourceRedirect(chat)}${qs}`;
|
||||
}
|
||||
|
||||
function getPublishRedirect(graphKey: string, segs: string[]) {
|
||||
const base = getGroupResourceRedirect(graphKey);
|
||||
if(segs.length === 3) {
|
||||
return `${base}/note/${segs[0]}`;
|
||||
} else if (segs.length === 4) {
|
||||
return `${base}/note/${segs[0]}?selected=${segs[2]}`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function getLinkRedirect(graphKey: string, segs: string[]) {
|
||||
const base = getGroupResourceRedirect(graphKey);
|
||||
if(segs.length === 1) {
|
||||
return `${base}/index/${segs[0]}`;
|
||||
} else if (segs.length === 3) {
|
||||
return `${base}/index/${segs[0]}?selected=${segs[1]}`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function getGraphRedirect(link: string) {
|
||||
const [,mark, ship, name, ...rest] = link.split('/');
|
||||
const graphKey = `${ship}/${name}`;
|
||||
switch(mark) {
|
||||
case 'graph-validator-dm':
|
||||
return `/~landscape/messages/dm/${ob.patp(rest[0])}`;
|
||||
case 'graph-validator-chat':
|
||||
return getChatRedirect(graphKey, rest);
|
||||
case 'graph-validator-publish':
|
||||
return getPublishRedirect(graphKey, rest);
|
||||
case 'graph-validator-link':
|
||||
return getLinkRedirect(graphKey, rest);
|
||||
case 'graph-validator-post':
|
||||
return getPostRedirect(graphKey, rest);
|
||||
default:
|
||||
return'';
|
||||
}
|
||||
}
|
||||
|
||||
function getInviteRedirect(link: string) {
|
||||
const [,,app,uid] = link.split('/');
|
||||
return `/invites/${app}/${uid}`;
|
||||
}
|
||||
|
||||
function getDmRedirect(link: string) {
|
||||
const [,,ship] = link.split('/');
|
||||
return `/~landscape/messages/dm/${ship}`;
|
||||
}
|
||||
function getGroupRedirect(link: string) {
|
||||
const [,,ship,name] = link.split('/');
|
||||
return `/~landscape/ship/${ship}/${name}`;
|
||||
}
|
||||
|
||||
function getNotificationRedirect(link: string) {
|
||||
if(link.startsWith('/graph-validator')) {
|
||||
return getGraphRedirect(link);
|
||||
} else if (link.startsWith('/invite')) {
|
||||
return getInviteRedirect(link);
|
||||
} else if (link.startsWith('/dm')) {
|
||||
return getDmRedirect(link);
|
||||
} else if (link.startsWith('/groups')) {
|
||||
return getGroupRedirect(link);
|
||||
}
|
||||
}
|
||||
|
||||
export const Content = (props) => {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
@ -119,7 +31,7 @@ export const Content = (props) => {
|
||||
useEffect(() => {
|
||||
const query = new URLSearchParams(location.search);
|
||||
if(mdLoaded && query.has('grid-note')) {
|
||||
history.push(getNotificationRedirect(query.get('grid-note')));
|
||||
history.push(getNotificationRedirect(query.get('grid-note')!));
|
||||
} else if(mdLoaded && query.has('grid-link')) {
|
||||
const link = decodeURIComponent(query.get('grid-link')!);
|
||||
history.push(`/perma${link}`);
|
||||
|
@ -1,7 +1,7 @@
|
||||
:~ title+'Groups'
|
||||
info+'A suite of applications to communicate on Urbit'
|
||||
color+0xee.5432
|
||||
glob-http+['https://bootstrap.urbit.org/glob-0v4d800.vqmrl.r0js2.ip98v.dd8sh.glob' 0v4d800.vqmrl.r0js2.ip98v.dd8sh]
|
||||
glob-http+['https://bootstrap.urbit.org/glob-0v1.9ge2e.2cb12.25972.u0l29.j0kuv.glob' 0v1.9ge2e.2cb12.25972.u0l29.j0kuv]
|
||||
base+'landscape'
|
||||
version+[1 3 5]
|
||||
website+'https://tlon.io'
|
||||
|
@ -1,20 +0,0 @@
|
||||
CC ?= cc
|
||||
AR ?= ar
|
||||
PREFIX ?= ./out
|
||||
|
||||
################################################################################
|
||||
|
||||
.PHONY: all test install clean
|
||||
|
||||
all: aes_siv.c aes_siv.h
|
||||
$(CC) $(CFLAGS) -Wall -Wextra -Wstrict-prototypes -Wconversion -O3 -fomit-frame-pointer -funroll-loops -ftree-vectorize -DNDEBUG -c aes_siv.c
|
||||
$(AR) rcs libaes_siv.a aes_siv.o
|
||||
|
||||
install: all
|
||||
@mkdir -p $(PREFIX)/lib/
|
||||
@mkdir -p $(PREFIX)/include/
|
||||
cp libaes_siv.a $(PREFIX)/lib/
|
||||
cp aes_siv.h $(PREFIX)/include/
|
||||
|
||||
clean:
|
||||
rm -rf ./out
|
@ -1,197 +0,0 @@
|
||||
# libaes_siv
|
||||
|
||||
This is an [RFC5297](https://tools.ietf.org/html/rfc5297)-compliant C
|
||||
implementation of AES-SIV written by Daniel Franke on behalf of
|
||||
[Akamai Technologies](https://www.akamai.com). It is published under
|
||||
the [Apache License
|
||||
(v2.0)](https://www.apache.org/licenses/LICENSE-2.0). It uses OpenSSL
|
||||
for the underlying
|
||||
[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) and
|
||||
[CMAC](https://en.wikipedia.org/wiki/One-key_MAC) implementations and
|
||||
follows a similar interface style.
|
||||
|
||||
An AES_SIV implementation forked from libaes_siv has been [merged into
|
||||
the OpenSSL master branch](https://github.com/openssl/openssl/pull/3540).
|
||||
However, the two implementations are not API-compatible; see section
|
||||
"OpenSSL API Comparison" below.
|
||||
|
||||
## Overview of SIV mode
|
||||
|
||||
Synthetic Initialization Vector (SIV) mode is a [block cipher mode of
|
||||
operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
|
||||
for [authenticated encryption with associated
|
||||
data](https://en.wikipedia.org/wiki/Authenticated_encryption) designed
|
||||
to be maximally resistant to accidental
|
||||
[nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) reuse. If
|
||||
two messages are accidentally encrypted using the same nonce and the
|
||||
same associated data, the attacker learns nothing except whether or
|
||||
not the plaintexts of the two messages are identical to each other.
|
||||
SIV mode also permits the nonce to be intentionally omitted, resulting
|
||||
in a [deterministic encryption
|
||||
scheme](https://en.wikipedia.org/wiki/Deterministic_encryption).
|
||||
|
||||
Here are a couple common situations where AES-SIV may be an
|
||||
appropriate choice of AEAD scheme:
|
||||
|
||||
1. You can't count on the system doing the encrypting to reliably
|
||||
generate a unique nonce for every message. For example, the system
|
||||
may be an embedded device with no good entropy source, or may be a
|
||||
VM subject to be snapshotted and restored.
|
||||
|
||||
2. You want your encryption to be deterministic so that an
|
||||
intermediating party such as a caching proxy, provided only with
|
||||
ciphertext, can perform deduplication.
|
||||
|
||||
The drawback to SIV mode is that it requires two passes over its
|
||||
input. This makes it potentially clumsy for use with large messages
|
||||
since the entire message must be held in memory at one time. SIV mode
|
||||
is also a bit slower than most widely-used block cipher modes (but
|
||||
can still be quite fast — see performance numbers below).
|
||||
|
||||
Be aware that with *any* encryption scheme, including SIV, repeating
|
||||
or omitting a nonce can still be [fatal to
|
||||
security](https://xkcd.com/257) if your plaintexts have low entropy,
|
||||
e.g., if each message consists only of a single bit.
|
||||
|
||||
Keys for SIV mode are twice the length of the keys for the underlying
|
||||
block cipher. For example, keys for AES-128-SIV are 256 bits long,
|
||||
and keys for AES-256-SIV are 512 bits long.
|
||||
|
||||
## Build instructions
|
||||
|
||||
Build dependencies:
|
||||
|
||||
* Any ISO C89 compiler (GCC or Clang recommended). No C99 language
|
||||
features are required, however `<stdint.h>` must be available and
|
||||
must define `uint64_t`. `char` must be 8 bits and arithmetic must be
|
||||
two's complement.
|
||||
* [CMake](https://cmake.org) >= 3.1
|
||||
* [OpenSSL](https://openssl.org) >=1.0.1 (libcrypto only). A recent
|
||||
release from the 1.0.2 branch or later is strongly recommended since
|
||||
1.0.1 was EOL'ed at the end of 2016. Furthermore, OpenSSL versions prior
|
||||
to 1.0.1n and 1.0.2b have known bugs which impact `libaes_siv` and
|
||||
will cause failures in its test suite. LibreSSL is not supported.
|
||||
* [Asciidoc](http://asciidoc.org) (only required for building man pages)
|
||||
|
||||
Running benchmarks requires a POSIX.1-2001 compliant OS, including
|
||||
the `clock_gettime` system call.
|
||||
|
||||
To build and install on POSIX-like platforms:
|
||||
```
|
||||
cmake . &&
|
||||
make &&
|
||||
make test &&
|
||||
sudo make install
|
||||
```
|
||||
|
||||
NOTE: Out-of-source builds are allowed, but out-of-source manpage builds
|
||||
require a2x's -D option, which may provoke an apparently bogus warning from a2x.
|
||||
|
||||
If you want to build on an OS X machine, install the Xcode development
|
||||
environment and the command line tools, then use either the Homebrew package
|
||||
manager or the MacPorts package manager to install cmake and OpenSSL.
|
||||
|
||||
Homebrew (https://brew.sh/):
|
||||
```
|
||||
brew install cmake openssl &&
|
||||
cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/openssl . &&
|
||||
make &&
|
||||
make test &&
|
||||
sudo make install
|
||||
```
|
||||
MacPorts (https://www.macports.org/):
|
||||
```
|
||||
sudo port install cmake openssl &&
|
||||
cmake . &&
|
||||
make &&
|
||||
make test &&
|
||||
sudo make install
|
||||
```
|
||||
|
||||
To create a native Windows build, you will first need to build
|
||||
OpenSSL. Install Visual Studio, CMake, ActiveState Perl, and NASM, and
|
||||
ensure that `nasm.exe` is somewhere in your `%PATH%`. From a VS developer
|
||||
command prompt, unpack the OpenSSL sources and run
|
||||
```
|
||||
perl Configure VC-WIN64A
|
||||
nmake
|
||||
```
|
||||
Then to build `libaes_siv`, run
|
||||
```
|
||||
cmake -G "NMake Makefiles" -DOPENSSL_ROOT_DIR=\path\to\openssl .
|
||||
nmake
|
||||
nmake test
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
See the manual pages for API documentation, and the test vectors
|
||||
in `tests.c` for simple usage examples. You can also use the `demo` command
|
||||
line program to encrypt and decrypt data.
|
||||
|
||||
## OpenSSL API Comparison
|
||||
|
||||
In December 2018, OpenSSL merged an AES-SIV implementation derived
|
||||
from libaes_siv. As of February 2019 this implementation has not been
|
||||
released yet; it will appear some time post-1.1.1. However, despite
|
||||
the two implementations' common ancestry, they are not API-compatible.
|
||||
The OpenSSL team had to make an ugly-but-necessary compromise in order
|
||||
to shoehorn SIV mode into OpenSSL's EVP API, which is a streaming API
|
||||
that was never designed to support SIV's two-pass operation. When used for
|
||||
SIV operations, the EVP API is forced to return an error if you invoke
|
||||
`EVP_(En|De)crypt_Update` more than once for the same message.
|
||||
|
||||
When designing libaes_siv, I rejected this behavior as an unacceptable
|
||||
breakdown of the API contract and opted to dispense with the EVP
|
||||
abstraction altogether rather than permit it to leak. libaes_siv's API
|
||||
remains stylistically similar to EVP, but is nonetheless distinct and
|
||||
avoids the above pitfall.
|
||||
|
||||
## Performance
|
||||
|
||||
On the author's Intel Core i7-6560U laptop, libaes_siv can process
|
||||
approximately 796 MiB of plaintext or ciphertext or 963 MiB of
|
||||
associated data per second using 256-bit keys
|
||||
(i.e., AES-128). Encrypting a zero-byte message takes approximately
|
||||
990ns. To obtain numbers for your own system, run `make bench &&
|
||||
./bench`.
|
||||
|
||||
## Software assurance
|
||||
|
||||
libaes_siv's test suite includes all test vectors from RFC 5297 and
|
||||
achieves 100% code coverage according to
|
||||
[gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html). It produces
|
||||
clean output from [Valgrind](https://valgrind.org) and from Clang's
|
||||
[undefined behavior
|
||||
sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html),
|
||||
and is verified using [ctgrind](https://github.com/agl/ctgrind) to run
|
||||
in constant time.
|
||||
|
||||
Nonetheless, libaes_siv should at present be considered beta-quality
|
||||
code. It has not yet been tested on platforms other than x86-64 Linux
|
||||
or benefited from any significant amount of user feedback, and
|
||||
the codebase is in need of additional review by cryptographers and
|
||||
expert C programmers.
|
||||
|
||||
## Bugs and pull requests
|
||||
|
||||
Use the GitHub issue tracker. For reporting sensitive security issues,
|
||||
contact the author directly. (Note: I no longer use PGP. Please
|
||||
request my Signal details if necessary).
|
||||
|
||||
## A note on version numbers
|
||||
|
||||
libaes_siv version numbers are of the form `<major>.<minor>.<patch>`
|
||||
and follow a semantic versioning scheme. The major version number
|
||||
will be incremented with any backward-incompatible ABI change. The
|
||||
minor version number will be incremented if new functionality is
|
||||
added without impacting ABI backward-compatibility. The patch
|
||||
version number will be incremented for releases that make no
|
||||
externally-visible changes.
|
||||
|
||||
As a result of this scheme, on ELF platforms, the .so version will
|
||||
be the same as the release version.
|
||||
|
||||
Version numbers indicate nothing about code quality or maturity. No
|
||||
code known or suspected to be less suitable for production use than
|
||||
previous releases will ever be tagged with a version number.
|
@ -1,2 +0,0 @@
|
||||
Vendoring of git@github.com:dfoxfranke/libaes_siv.git.
|
||||
Code from commit 509550e92a416172b9b8255e275f3a04d5fd4545
|
@ -1,594 +0,0 @@
|
||||
/* Copyright (c) 2017-2019 Akamai Technologies, Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#define _ISOC99_SOURCE 1
|
||||
|
||||
#include "config.h"
|
||||
#include "aes_siv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#ifdef ENABLE_DEBUG_OUTPUT
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
/* For _byteswap_uint64 */
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef ENABLE_CTGRIND
|
||||
#include <ctgrind.h>
|
||||
#endif
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
#error "libaes_siv requires an 8-bit char type"
|
||||
#endif
|
||||
|
||||
#if -1 != ~0
|
||||
#error "libaes_siv requires a two's-complement architecture"
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
|
||||
#undef inline
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define inline __inline__
|
||||
#elif defined(_MSC_VER)
|
||||
#define inline __inline
|
||||
#else
|
||||
#define inline
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define LIKELY(cond) __builtin_expect(cond, 1)
|
||||
#define UNLIKELY(cond) __builtin_expect(cond, 0)
|
||||
#else
|
||||
#define LIKELY(cond) cond
|
||||
#define UNLIKELY(cond) cond
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_CTGRIND
|
||||
static inline void ct_poison(const void *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
}
|
||||
static inline void ct_unpoison(const void *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void debug(const char *label, const unsigned char *hex, size_t len) {
|
||||
/* ENABLE_CTGRIND has to override ENABLE_DEBUG_OUTPUT since sensitive data
|
||||
gets printed.
|
||||
*/
|
||||
#if defined(ENABLE_DEBUG_OUTPUT) && !defined(ENABLE_CTGRIND)
|
||||
size_t i;
|
||||
printf("%16s: ", label);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
printf("%.2x", (int)hex[i]);
|
||||
if (i > 0 && i % 4 == 3) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
#else
|
||||
(void)label;
|
||||
(void)hex;
|
||||
(void)len;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef union block_un {
|
||||
uint64_t word[2];
|
||||
unsigned char byte[16];
|
||||
} block;
|
||||
|
||||
const union {
|
||||
uint64_t word;
|
||||
char byte[8];
|
||||
} endian = {0x0102030405060708};
|
||||
|
||||
#define I_AM_BIG_ENDIAN (endian.byte[0] == 1 && \
|
||||
endian.byte[1] == 2 && \
|
||||
endian.byte[2] == 3 && \
|
||||
endian.byte[3] == 4 && \
|
||||
endian.byte[4] == 5 && \
|
||||
endian.byte[5] == 6 && \
|
||||
endian.byte[6] == 7 && \
|
||||
endian.byte[7] == 8)
|
||||
|
||||
#define I_AM_LITTLE_ENDIAN (endian.byte[0] == 8 && \
|
||||
endian.byte[1] == 7 && \
|
||||
endian.byte[2] == 6 && \
|
||||
endian.byte[3] == 5 && \
|
||||
endian.byte[4] == 4 && \
|
||||
endian.byte[5] == 3 && \
|
||||
endian.byte[6] == 2 && \
|
||||
endian.byte[7] == 1)
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
static inline uint64_t bswap64(uint64_t x) { return __builtin_bswap64(x); }
|
||||
#elif defined(_MSC_VER)
|
||||
static inline uint64_t bswap64(uint64_t x) { return _byteswap_uint64(x); }
|
||||
#else
|
||||
|
||||
static inline uint32_t rotl(uint32_t x) { return (x << 8) | (x >> 24); }
|
||||
static inline uint32_t rotr(uint32_t x) { return (x >> 8) | (x << 24); }
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x) {
|
||||
uint32_t high = (uint32_t)(x >> 32);
|
||||
uint32_t low = (uint32_t)x;
|
||||
|
||||
high = (rotl(high) & 0x00ff00ff) | (rotr(high) & 0xff00ff00);
|
||||
low = (rotl(low) & 0x00ff00ff) | (rotr(low) & 0xff00ff00);
|
||||
return ((uint64_t)low) << 32 | (uint64_t)high;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint64_t getword(block const *block, size_t i) {
|
||||
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
|
||||
if (I_AM_BIG_ENDIAN) {
|
||||
return block->word[i];
|
||||
} else if (I_AM_LITTLE_ENDIAN) {
|
||||
return bswap64(block->word[i]);
|
||||
} else {
|
||||
#endif
|
||||
i <<= 3;
|
||||
return ((uint64_t)block->byte[i + 7]) |
|
||||
((uint64_t)block->byte[i + 6] << 8) |
|
||||
((uint64_t)block->byte[i + 5] << 16) |
|
||||
((uint64_t)block->byte[i + 4] << 24) |
|
||||
((uint64_t)block->byte[i + 3] << 32) |
|
||||
((uint64_t)block->byte[i + 2] << 40) |
|
||||
((uint64_t)block->byte[i + 1] << 48) |
|
||||
((uint64_t)block->byte[i] << 56);
|
||||
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void putword(block *block, size_t i, uint64_t x) {
|
||||
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
|
||||
if (I_AM_BIG_ENDIAN) {
|
||||
block->word[i] = x;
|
||||
} else if (I_AM_LITTLE_ENDIAN) {
|
||||
block->word[i] = bswap64(x);
|
||||
} else {
|
||||
#endif
|
||||
i <<= 3;
|
||||
block->byte[i] = (unsigned char)(x >> 56);
|
||||
block->byte[i + 1] = (unsigned char)((x >> 48) & 0xff);
|
||||
block->byte[i + 2] = (unsigned char)((x >> 40) & 0xff);
|
||||
block->byte[i + 3] = (unsigned char)((x >> 32) & 0xff);
|
||||
block->byte[i + 4] = (unsigned char)((x >> 24) & 0xff);
|
||||
block->byte[i + 5] = (unsigned char)((x >> 16) & 0xff);
|
||||
block->byte[i + 6] = (unsigned char)((x >> 8) & 0xff);
|
||||
block->byte[i + 7] = (unsigned char)(x & 0xff);
|
||||
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void xorblock(block *x, block const *y) {
|
||||
x->word[0] ^= y->word[0];
|
||||
x->word[1] ^= y->word[1];
|
||||
}
|
||||
|
||||
/* Doubles `block`, which is 16 bytes representing an element
|
||||
of GF(2**128) modulo the irreducible polynomial
|
||||
x**128 + x**7 + x**2 + x + 1. */
|
||||
static inline void dbl(block *block) {
|
||||
uint64_t high = getword(block, 0);
|
||||
uint64_t low = getword(block, 1);
|
||||
uint64_t high_carry = high & (((uint64_t)1) << 63);
|
||||
uint64_t low_carry = low & (((uint64_t)1) << 63);
|
||||
/* Assumes two's-complement arithmetic */
|
||||
int64_t low_mask = -((int64_t)(high_carry >> 63)) & 0x87;
|
||||
uint64_t high_mask = low_carry >> 63;
|
||||
high = (high << 1) | high_mask;
|
||||
low = (low << 1) ^ (uint64_t)low_mask;
|
||||
putword(block, 0, high);
|
||||
putword(block, 1, low);
|
||||
}
|
||||
|
||||
struct AES_SIV_CTX_st {
|
||||
/* d stores intermediate results of S2V; it corresponds to D from the
|
||||
pseudocode in section 2.4 of RFC 5297. */
|
||||
block d;
|
||||
EVP_CIPHER_CTX *cipher_ctx;
|
||||
/* SIV_AES_Init() sets up cmac_ctx_init. cmac_ctx is a scratchpad used
|
||||
by SIV_AES_AssociateData() and SIV_AES_(En|De)cryptFinal. */
|
||||
CMAC_CTX *cmac_ctx_init, *cmac_ctx;
|
||||
};
|
||||
|
||||
void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_CIPHER_CTX_reset(ctx->cipher_ctx);
|
||||
#else
|
||||
EVP_CIPHER_CTX_cleanup(ctx->cipher_ctx);
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER <= 0x10100060L
|
||||
/* Workaround for an OpenSSL bug that causes a double free
|
||||
if you call CMAC_CTX_cleanup() before CMAC_CTX_free().
|
||||
https://github.com/openssl/openssl/pull/2798
|
||||
*/
|
||||
CMAC_CTX_free(ctx->cmac_ctx_init);
|
||||
ctx->cmac_ctx_init = CMAC_CTX_new();
|
||||
CMAC_CTX_free(ctx->cmac_ctx);
|
||||
ctx->cmac_ctx = CMAC_CTX_new();
|
||||
#else
|
||||
CMAC_CTX_cleanup(ctx->cmac_ctx_init);
|
||||
CMAC_CTX_cleanup(ctx->cmac_ctx);
|
||||
#endif
|
||||
OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
|
||||
}
|
||||
|
||||
void AES_SIV_CTX_free(AES_SIV_CTX *ctx) {
|
||||
if (ctx) {
|
||||
EVP_CIPHER_CTX_free(ctx->cipher_ctx);
|
||||
/* Prior to OpenSSL 1.0.2b, CMAC_CTX_free() crashes on NULL */
|
||||
if (LIKELY(ctx->cmac_ctx_init != NULL)) {
|
||||
CMAC_CTX_free(ctx->cmac_ctx_init);
|
||||
}
|
||||
if (LIKELY(ctx->cmac_ctx != NULL)) {
|
||||
CMAC_CTX_free(ctx->cmac_ctx);
|
||||
}
|
||||
OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
AES_SIV_CTX *AES_SIV_CTX_new(void) {
|
||||
AES_SIV_CTX *ctx = OPENSSL_malloc(sizeof(struct AES_SIV_CTX_st));
|
||||
if (UNLIKELY(ctx == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->cipher_ctx = EVP_CIPHER_CTX_new();
|
||||
ctx->cmac_ctx_init = CMAC_CTX_new();
|
||||
ctx->cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
if (UNLIKELY(ctx->cipher_ctx == NULL ||
|
||||
ctx->cmac_ctx_init == NULL ||
|
||||
ctx->cmac_ctx == NULL)) {
|
||||
AES_SIV_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const *src) {
|
||||
memcpy(&dst->d, &src->d, sizeof src->d);
|
||||
if(UNLIKELY(EVP_CIPHER_CTX_copy(dst->cipher_ctx, src->cipher_ctx)
|
||||
!= 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(CMAC_CTX_copy(dst->cmac_ctx_init, src->cmac_ctx_init)
|
||||
!= 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* Not necessary to copy cmac_ctx since it's just temporary
|
||||
* storage */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const *key, size_t key_len) {
|
||||
static const unsigned char zero[] = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0};
|
||||
size_t out_len;
|
||||
int ret = 0;
|
||||
|
||||
ct_poison(key, key_len);
|
||||
|
||||
switch (key_len) {
|
||||
case 32:
|
||||
if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 16,
|
||||
EVP_aes_128_cbc(), NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
|
||||
EVP_aes_128_ctr(),
|
||||
NULL, key + 16, NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 48:
|
||||
if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 24,
|
||||
EVP_aes_192_cbc(), NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
|
||||
EVP_aes_192_ctr(),
|
||||
NULL, key + 24, NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 64:
|
||||
if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 32,
|
||||
EVP_aes_256_cbc(), NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
|
||||
EVP_aes_256_ctr(),
|
||||
NULL, key + 32, NULL) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, zero, sizeof zero) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
out_len = sizeof ctx->d;
|
||||
if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, ctx->d.byte, &out_len) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
debug("CMAC(zero)", ctx->d.byte, out_len);
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
ct_unpoison(key, key_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const *data,
|
||||
size_t len) {
|
||||
block cmac_out;
|
||||
size_t out_len = sizeof cmac_out;
|
||||
int ret = 0;
|
||||
|
||||
ct_poison(data, len);
|
||||
|
||||
dbl(&ctx->d);
|
||||
debug("double()", ctx->d.byte, 16);
|
||||
|
||||
if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, data, len) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, cmac_out.byte, &out_len) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
assert(out_len == 16);
|
||||
debug("CMAC(ad)", cmac_out.byte, 16);
|
||||
|
||||
xorblock(&ctx->d, &cmac_out);
|
||||
debug("xor", ctx->d.byte, 16);
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
ct_unpoison(data, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int do_s2v_p(AES_SIV_CTX *ctx, block *out,
|
||||
unsigned char const* in, size_t len) {
|
||||
block t;
|
||||
size_t out_len = sizeof out->byte;
|
||||
|
||||
if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len >= 16) {
|
||||
if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, in, len - 16) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
debug("xorend part 1", in, len - 16);
|
||||
memcpy(&t, in + (len-16), 16);
|
||||
xorblock(&t, &ctx->d);
|
||||
debug("xorend part 2", t.byte, 16);
|
||||
if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
size_t i;
|
||||
memcpy(&t, in, len);
|
||||
t.byte[len] = 0x80;
|
||||
for(i = len + 1; i < 16; i++) {
|
||||
t.byte[i] = 0;
|
||||
}
|
||||
debug("pad", t.byte, 16);
|
||||
dbl(&ctx->d);
|
||||
xorblock(&t, &ctx->d);
|
||||
debug("xor", t.byte, 16);
|
||||
if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(UNLIKELY(CMAC_Final(ctx->cmac_ctx, out->byte, &out_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
assert(out_len == 16);
|
||||
debug("CMAC(final)", out->byte, 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int do_encrypt(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
unsigned char const *in, size_t len, block *icv) {
|
||||
#ifdef ENABLE_DEBUG_TINY_CHUNK_SIZE
|
||||
const int chunk_size = 7;
|
||||
#else
|
||||
const int chunk_size = 1 << 30;
|
||||
#endif
|
||||
size_t len_remaining = len;
|
||||
int out_len;
|
||||
int ret;
|
||||
|
||||
if(UNLIKELY(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, icv->byte)
|
||||
!= 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(UNLIKELY(len_remaining > (size_t)chunk_size)) {
|
||||
out_len = chunk_size;
|
||||
if(UNLIKELY(EVP_EncryptUpdate(ctx, out, &out_len, in, out_len)
|
||||
!= 1)) {
|
||||
return 0;
|
||||
}
|
||||
assert(out_len == chunk_size);
|
||||
out += out_len;
|
||||
in += out_len;
|
||||
len_remaining -= (size_t)out_len;
|
||||
}
|
||||
|
||||
out_len = (int)len_remaining;
|
||||
ret = EVP_EncryptUpdate(ctx, out, &out_len, in, out_len);
|
||||
assert(!ret || out_len == (int)len_remaining);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx, unsigned char *v_out,
|
||||
unsigned char *c_out, unsigned char const *plaintext,
|
||||
size_t len) {
|
||||
block q;
|
||||
int ret = 0;
|
||||
|
||||
ct_poison(plaintext, len);
|
||||
|
||||
if(UNLIKELY(do_s2v_p(ctx, &q, plaintext, len) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ct_unpoison(&q, sizeof q);
|
||||
memcpy(v_out, &q, 16);
|
||||
q.byte[8] &= 0x7f;
|
||||
q.byte[12] &= 0x7f;
|
||||
|
||||
if(UNLIKELY(do_encrypt(ctx->cipher_ctx, c_out, plaintext, len, &q)
|
||||
!= 1)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
debug("ciphertext", c_out, len);
|
||||
|
||||
done:
|
||||
ct_unpoison(plaintext, len);
|
||||
ct_unpoison(c_out, len);
|
||||
ct_unpoison(v_out, 16);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
|
||||
unsigned char const *v, unsigned char const *c,
|
||||
size_t len) {
|
||||
block t, q;
|
||||
size_t i;
|
||||
uint64_t result;
|
||||
int ret = 0;
|
||||
|
||||
ct_poison(c, len);
|
||||
|
||||
memcpy(&q, v, 16);
|
||||
q.byte[8] &= 0x7f;
|
||||
q.byte[12] &= 0x7f;
|
||||
|
||||
if(UNLIKELY(do_encrypt(ctx->cipher_ctx, out, c, len, &q) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
debug("plaintext", out, len);
|
||||
|
||||
if(UNLIKELY(do_s2v_p(ctx, &t, out, len) != 1)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
t.byte[i] ^= v[i];
|
||||
}
|
||||
|
||||
result = t.word[0] | t.word[1];
|
||||
ct_unpoison(&result, sizeof result);
|
||||
ret = !result;
|
||||
|
||||
if(ret) {
|
||||
ct_unpoison(out, len);
|
||||
} else {
|
||||
OPENSSL_cleanse(out, len);
|
||||
}
|
||||
|
||||
done:
|
||||
ct_unpoison(c, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AES_SIV_Encrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
|
||||
unsigned char const *key, size_t key_len,
|
||||
unsigned char const *nonce, size_t nonce_len,
|
||||
unsigned char const *plaintext, size_t plaintext_len,
|
||||
unsigned char const *ad, size_t ad_len) {
|
||||
if (UNLIKELY(*out_len < plaintext_len + 16)) {
|
||||
return 0;
|
||||
}
|
||||
*out_len = plaintext_len + 16;
|
||||
|
||||
if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (nonce != NULL &&
|
||||
UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(AES_SIV_EncryptFinal(ctx, out, out + 16, plaintext,
|
||||
plaintext_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("IV || C", out, *out_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AES_SIV_Decrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
|
||||
unsigned char const *key, size_t key_len,
|
||||
unsigned char const *nonce, size_t nonce_len,
|
||||
unsigned char const *ciphertext, size_t ciphertext_len,
|
||||
unsigned char const *ad, size_t ad_len) {
|
||||
if (UNLIKELY(ciphertext_len < 16)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(*out_len < ciphertext_len - 16)) {
|
||||
return 0;
|
||||
}
|
||||
*out_len = ciphertext_len - 16;
|
||||
|
||||
if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (nonce != NULL &&
|
||||
UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (UNLIKELY(AES_SIV_DecryptFinal(ctx, out, ciphertext, ciphertext + 16,
|
||||
ciphertext_len - 16) != 1)) {
|
||||
return 0;
|
||||
}
|
||||
debug("plaintext", out, *out_len);
|
||||
return 1;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/* Copyright (c) 2017-2019 Akamai Technologies, Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef AES_SIV_H_
|
||||
#define AES_SIV_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define LIBAES_SIV_VERSION_MAJOR 1
|
||||
#define LIBAES_SIV_VERSION_MINOR 0
|
||||
#define LIBAES_SIV_VERSION_PATCH 1
|
||||
|
||||
#define LIBAES_SIV_VERSION ((LIBAES_SIV_VERSION_MAJOR << 16) + \
|
||||
(LIBAES_SIV_VERSION_MINOR << 8) + \
|
||||
LIBAES_SIV_VERSION_PATCH)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct AES_SIV_CTX_st AES_SIV_CTX;
|
||||
|
||||
AES_SIV_CTX *AES_SIV_CTX_new(void);
|
||||
int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const *src);
|
||||
void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx);
|
||||
void AES_SIV_CTX_free(AES_SIV_CTX *ctx);
|
||||
|
||||
int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const *key, size_t key_len);
|
||||
int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const *data,
|
||||
size_t len);
|
||||
int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx, unsigned char *v_out,
|
||||
unsigned char *c_out, unsigned char const *plaintext,
|
||||
size_t len);
|
||||
int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
|
||||
unsigned char const *v, unsigned char const *c,
|
||||
size_t len);
|
||||
|
||||
int AES_SIV_Encrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
|
||||
unsigned char const *key, size_t key_len,
|
||||
unsigned char const *nonce, size_t nonce_len,
|
||||
unsigned char const *plaintext, size_t plaintext_len,
|
||||
unsigned char const *ad, size_t ad_len);
|
||||
|
||||
int AES_SIV_Decrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
|
||||
unsigned char const *key, size_t key_len,
|
||||
unsigned char const *nonce, size_t nonce_len,
|
||||
unsigned char const *ciphertext, size_t ciphertext_len,
|
||||
unsigned char const *ad, size_t ad_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,19 +0,0 @@
|
||||
#ifndef AES_SIV_CONFIG_H_
|
||||
#define AES_SIV_CONFIG_H_
|
||||
|
||||
/* Enable ct_poison() and ct_unpoison() hooks for testing with
|
||||
ctgrind. */
|
||||
/* #undef ENABLE_CTGRIND */
|
||||
|
||||
/* Enable this to get test coverage for the portable versions of
|
||||
putword() and getword() when you don't happen to have a PDP-11
|
||||
in your test farm.
|
||||
*/
|
||||
/* #undef ENABLE_DEBUG_WEIRD_ENDIAN */
|
||||
|
||||
/* Enable this to get test coverage for the while loop in do_encrypt()
|
||||
without having to have a multi-gigabyte test case that'll take
|
||||
forever for Valgrind to crunch through
|
||||
*/
|
||||
/* #undef ENABLE_DEBUG_TINY_CHUNK_SIZE */
|
||||
#endif
|
@ -53,3 +53,13 @@ export function docketInstall(ship: string, desk: string): Poke<any> {
|
||||
json: `${ship}/${desk}`
|
||||
};
|
||||
}
|
||||
|
||||
export function allyShip(ship: string): Poke<any> {
|
||||
return {
|
||||
app: 'treaty',
|
||||
mark: 'ally-update-0',
|
||||
json: {
|
||||
add: ship
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -70,8 +70,6 @@ export const opened = harkAction({
|
||||
opened: null
|
||||
});
|
||||
|
||||
|
||||
|
||||
export const markCountAsRead = (place: HarkPlace): Poke<unknown> =>
|
||||
harkAction({
|
||||
'read-count': place
|
||||
@ -147,3 +145,10 @@ export function harkBinEq(a: HarkBin, b: HarkBin): boolean {
|
||||
a.path === b.path
|
||||
);
|
||||
}
|
||||
|
||||
export function harkLidToId(lid: HarkLid): string {
|
||||
if('time' in lid) {
|
||||
return `archive-${lid.time}`;
|
||||
}
|
||||
return Object.keys(lid)[0];
|
||||
}
|
||||
|
1
pkg/urbit/.gitattributes
vendored
1
pkg/urbit/.gitattributes
vendored
@ -3,3 +3,4 @@
|
||||
tests export-ignore
|
||||
hashtable_tests export-ignore
|
||||
shell.nix export-ignore
|
||||
*.patch -text
|
||||
|
2
pkg/urbit/.gitignore
vendored
2
pkg/urbit/.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
# Configuration Result
|
||||
/config.mk
|
||||
/include/config.h
|
||||
/include/ca-bundle.h
|
||||
/include/ivory.h
|
||||
|
@ -1,4 +1,5 @@
|
||||
include config.mk
|
||||
include $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.mk))
|
||||
|
||||
jets = jets/tree.c $(wildcard jets/*/*.c)
|
||||
noun = $(wildcard noun/*.c)
|
||||
@ -9,7 +10,9 @@ worker = $(wildcard worker/*.c)
|
||||
tests = $(wildcard tests/*.c)
|
||||
bench = $(wildcard bench/*.c)
|
||||
|
||||
common = $(jets) $(noun) $(ur) $(vere)
|
||||
compat := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.c))
|
||||
|
||||
common = $(jets) $(noun) $(ur) $(vere) $(compat)
|
||||
headers = $(shell find include -type f)
|
||||
|
||||
common_objs = $(shell echo $(common) | sed 's/\.c/.o/g')
|
||||
@ -29,7 +32,7 @@ CFLAGS := $(CFLAGS)
|
||||
|
||||
################################################################################
|
||||
|
||||
.PHONY: all test clean mkproper
|
||||
.PHONY: all test clean mrproper
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -74,9 +77,11 @@ build/urbit-worker: $(common_objs) $(worker_objs)
|
||||
@mkdir -p ./build
|
||||
@$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
%.o: %.c $(headers)
|
||||
# CCDEPS and CCEXTRA are empty except in MingW build,
|
||||
# which uses them to inject a C source transform step
|
||||
%.o: %.c $(headers) $(CCDEPS)
|
||||
@echo CC $<
|
||||
@$(CC) -I./include $(CFLAGS) -c $< -o $@
|
||||
@$(CC) -I./include $(CFLAGS) $< $(CCEXTRA) -c -o $@
|
||||
|
||||
tags: $(all_srcs) $(headers)
|
||||
ctags $^
|
||||
|
22
pkg/urbit/compat/create-include-files.sh
Executable file
22
pkg/urbit/compat/create-include-files.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# support running off a tarball that doesn't contain binary pills
|
||||
(( $($1 ../../bin/ivory.pill) > 512 )) || curl -L https://github.com/urbit/urbit/raw/urbit-v$URBIT_VERSION/bin/ivory.pill > ../../bin/ivory.pill
|
||||
|
||||
poor_mans_xxd () {
|
||||
cch=0
|
||||
echo "unsigned char $2[] = {"
|
||||
while IFS='' read line
|
||||
do
|
||||
for i in $line
|
||||
do
|
||||
echo -n " 0x$i,"
|
||||
cch=$((cch+1))
|
||||
done
|
||||
echo
|
||||
done < <(od -An -v -tx1 $1)
|
||||
echo "};"
|
||||
echo "unsigned int $2_len = $cch;"
|
||||
}
|
||||
|
||||
[ -e include/ca-bundle.h ] || poor_mans_xxd $2 include_ca_bundle_crt >include/ca-bundle.h
|
||||
[ -e include/ivory.h ] || poor_mans_xxd ../../bin/ivory.pill u3_Ivory_pill >include/ivory.h
|
14
pkg/urbit/compat/m1brew/compat.mk
Normal file
14
pkg/urbit/compat/m1brew/compat.mk
Normal file
@ -0,0 +1,14 @@
|
||||
# paths to brew packages
|
||||
CFLAGS := $(CFLAGS) -I/opt/homebrew/include
|
||||
LDFLAGS := $(LDFLAGS) -L/opt/homebrew/lib
|
||||
# force linker to use static libraries
|
||||
LDFLAGS := $(shell compat/m1brew/use-static-libs.sh $(LDFLAGS))
|
||||
# add extra osx libraries
|
||||
LDFLAGS := $(LDFLAGS) -framework SystemConfiguration
|
||||
|
||||
ifdef debug
|
||||
CFLAGS := $(CFLAGS) -O0 -g
|
||||
else
|
||||
# clang hangs on noun/allocate.c if -g is specified with -O3
|
||||
CFLAGS := $(CFLAGS) -O3
|
||||
endif
|
12
pkg/urbit/compat/m1brew/ent.patch
Normal file
12
pkg/urbit/compat/m1brew/ent.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/configure b/configure
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -15,7 +15,7 @@ do
|
||||
log "Trying IMPL=$IMPL"
|
||||
|
||||
if IMPL=$impl make >/dev/null 2>/dev/null
|
||||
- then sed -i 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile
|
||||
+ then sed -i "" 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile
|
||||
log "IMPL=$IMPL works"
|
||||
exit 0
|
||||
else log "IMPL=$IMPL failed"
|
13
pkg/urbit/compat/m1brew/murmur3.patch
Normal file
13
pkg/urbit/compat/m1brew/murmur3.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/makefile b/makefile
|
||||
--- a/makefile
|
||||
+++ b/makefile
|
||||
@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h
|
||||
$(CC) -fPIC -O3 -c murmur3.c
|
||||
$(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so
|
||||
|
||||
+static: murmur3.c murmur3.h
|
||||
+ $(CC) -fPIC -O3 -c murmur3.c
|
||||
+ $(AR) rcs libmurmur3.a murmur3.o
|
||||
+
|
||||
clean:
|
||||
rm -rf example *.o *.so
|
85
pkg/urbit/compat/m1brew/softfloat3.patch
Normal file
85
pkg/urbit/compat/m1brew/softfloat3.patch
Normal file
@ -0,0 +1,85 @@
|
||||
diff --git a/build/template-FAST_INT64/Makefile b/build/template-FAST_INT64/Makefile
|
||||
--- a/build/template-FAST_INT64/Makefile
|
||||
+++ b/build/template-FAST_INT64/Makefile
|
||||
@@ -34,28 +34,27 @@
|
||||
#
|
||||
#=============================================================================
|
||||
|
||||
-# Edit lines marked with `==>'. See "SoftFloat-source.html".
|
||||
+SOURCE_DIR ?= ../../source
|
||||
+SPECIALIZE_TYPE ?= 8086-SSE
|
||||
|
||||
-==> SOURCE_DIR ?= ../../source
|
||||
-==> SPECIALIZE_TYPE ?= 8086
|
||||
+SOFTFLOAT_OPTS ?= \
|
||||
+ -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \
|
||||
+ -DSOFTFLOAT_FAST_DIV64TO32
|
||||
|
||||
-==> SOFTFLOAT_OPTS ?= \
|
||||
-==> -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \
|
||||
-==> -DSOFTFLOAT_FAST_DIV64TO32
|
||||
+DELETE = rm -f
|
||||
+C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include
|
||||
+COMPILE_C = \
|
||||
+ cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@
|
||||
+MAKELIB = ar crs $@
|
||||
+LIBNAME = libsoftfloat3
|
||||
|
||||
-==> DELETE = rm -f
|
||||
-==> C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include
|
||||
-==> COMPILE_C = \
|
||||
-==> cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@
|
||||
-==> MAKELIB = ar crs $@
|
||||
+OBJ = .o
|
||||
+LIB = .a
|
||||
|
||||
-==> OBJ = .o
|
||||
-==> LIB = .a
|
||||
-
|
||||
-==> OTHER_HEADERS =
|
||||
+OTHER_HEADERS =
|
||||
|
||||
.PHONY: all
|
||||
-all: softfloat$(LIB)
|
||||
+all: $(LIBNAME)$(LIB)
|
||||
|
||||
OBJS_PRIMITIVES = \
|
||||
s_eq128$(OBJ) \
|
||||
@@ -381,11 +380,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c
|
||||
$(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c
|
||||
$(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c
|
||||
|
||||
-softfloat$(LIB): $(OBJS_ALL)
|
||||
+$(LIBNAME)$(LIB): $(OBJS_ALL)
|
||||
$(DELETE) $@
|
||||
$(MAKELIB) $^
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
- $(DELETE) $(OBJS_ALL) softfloat$(LIB)
|
||||
+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB)
|
||||
|
||||
diff --git a/build/template-FAST_INT64/platform.h b/build/template-FAST_INT64/platform.h
|
||||
--- a/build/template-FAST_INT64/platform.h
|
||||
+++ b/build/template-FAST_INT64/platform.h
|
||||
@@ -34,17 +34,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
-// Edit lines marked with `==>'. See "SoftFloat-source.html".
|
||||
-
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
-==> #define LITTLEENDIAN 1
|
||||
+#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
-==> #define INLINE inline
|
||||
+#define INLINE inline
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
-==> #define THREAD_LOCAL _Thread_local
|
||||
+#define THREAD_LOCAL _Thread_local
|
||||
|
23
pkg/urbit/compat/m1brew/use-static-libs.sh
Executable file
23
pkg/urbit/compat/m1brew/use-static-libs.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
declare -a ldirs
|
||||
for i in $@
|
||||
do
|
||||
case $i in
|
||||
-L*) ldirs+=(${i:2});;
|
||||
esac
|
||||
done
|
||||
for i in $@
|
||||
do
|
||||
case $i in
|
||||
-l*)
|
||||
lib=$(find ${ldirs[@]} -name lib${i:2}.a)
|
||||
if [ "$lib" != "" ]
|
||||
then
|
||||
echo $lib
|
||||
else
|
||||
echo $i
|
||||
fi;;
|
||||
*) echo $i;;
|
||||
esac
|
||||
done
|
355
pkg/urbit/compat/mingw/compat.c
Normal file
355
pkg/urbit/compat/mingw/compat.c
Normal file
@ -0,0 +1,355 @@
|
||||
#include "c/portable.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/utime.h>
|
||||
#include <windows.h>
|
||||
|
||||
// set default CRT file mode to binary
|
||||
// note that mingw binmode.o does nothing
|
||||
#undef _fmode
|
||||
int _fmode = _O_BINARY;
|
||||
|
||||
// set standard I/O fds to binary too, because
|
||||
// MSVCRT creates them before MingW sets _fmode
|
||||
static void __attribute__ ((constructor)) _set_stdio_to_binary()
|
||||
{
|
||||
_setmode(0, _O_BINARY);
|
||||
_setmode(1, _O_BINARY);
|
||||
_setmode(2, _O_BINARY);
|
||||
}
|
||||
|
||||
// from https://github.com/git/git/blob/master/compat/mingw.c
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
int err_win_to_posix(DWORD winerr)
|
||||
{
|
||||
int error = ENOSYS;
|
||||
switch(winerr) {
|
||||
case ERROR_ACCESS_DENIED: error = EACCES; break;
|
||||
case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
|
||||
case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
|
||||
case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
|
||||
case ERROR_ALREADY_EXISTS: error = EEXIST; break;
|
||||
case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
|
||||
case ERROR_BAD_COMMAND: error = EIO; break;
|
||||
case ERROR_BAD_DEVICE: error = ENODEV; break;
|
||||
case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
|
||||
case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
|
||||
case ERROR_BAD_FORMAT: error = ENOEXEC; break;
|
||||
case ERROR_BAD_LENGTH: error = EINVAL; break;
|
||||
case ERROR_BAD_PATHNAME: error = ENOENT; break;
|
||||
case ERROR_BAD_PIPE: error = EPIPE; break;
|
||||
case ERROR_BAD_UNIT: error = ENODEV; break;
|
||||
case ERROR_BAD_USERNAME: error = EINVAL; break;
|
||||
case ERROR_BROKEN_PIPE: error = EPIPE; break;
|
||||
case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
|
||||
case ERROR_BUSY: error = EBUSY; break;
|
||||
case ERROR_BUSY_DRIVE: error = EBUSY; break;
|
||||
case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
|
||||
case ERROR_CANNOT_MAKE: error = EACCES; break;
|
||||
case ERROR_CANTOPEN: error = EIO; break;
|
||||
case ERROR_CANTREAD: error = EIO; break;
|
||||
case ERROR_CANTWRITE: error = EIO; break;
|
||||
case ERROR_CRC: error = EIO; break;
|
||||
case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
|
||||
case ERROR_DEVICE_IN_USE: error = EBUSY; break;
|
||||
case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
|
||||
case ERROR_DIRECTORY: error = EINVAL; break;
|
||||
case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
|
||||
case ERROR_DISK_CHANGE: error = EIO; break;
|
||||
case ERROR_DISK_FULL: error = ENOSPC; break;
|
||||
case ERROR_DRIVE_LOCKED: error = EBUSY; break;
|
||||
case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
|
||||
case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
|
||||
case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
|
||||
case ERROR_FILE_EXISTS: error = EEXIST; break;
|
||||
case ERROR_FILE_INVALID: error = ENODEV; break;
|
||||
case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
|
||||
case ERROR_GEN_FAILURE: error = EIO; break;
|
||||
case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
|
||||
case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
|
||||
case ERROR_INVALID_ACCESS: error = EACCES; break;
|
||||
case ERROR_INVALID_ADDRESS: error = EFAULT; break;
|
||||
case ERROR_INVALID_BLOCK: error = EFAULT; break;
|
||||
case ERROR_INVALID_DATA: error = EINVAL; break;
|
||||
case ERROR_INVALID_DRIVE: error = ENODEV; break;
|
||||
case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
|
||||
case ERROR_INVALID_FLAGS: error = EINVAL; break;
|
||||
case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
|
||||
case ERROR_INVALID_HANDLE: error = EBADF; break;
|
||||
case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
|
||||
case ERROR_INVALID_NAME: error = EINVAL; break;
|
||||
case ERROR_INVALID_OWNER: error = EINVAL; break;
|
||||
case ERROR_INVALID_PARAMETER: error = EINVAL; break;
|
||||
case ERROR_INVALID_PASSWORD: error = EPERM; break;
|
||||
case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
|
||||
case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
|
||||
case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
|
||||
case ERROR_INVALID_WORKSTATION: error = EACCES; break;
|
||||
case ERROR_IO_DEVICE: error = EIO; break;
|
||||
case ERROR_IO_INCOMPLETE: error = EINTR; break;
|
||||
case ERROR_LOCKED: error = EBUSY; break;
|
||||
case ERROR_LOCK_VIOLATION: error = EACCES; break;
|
||||
case ERROR_LOGON_FAILURE: error = EACCES; break;
|
||||
case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
|
||||
case ERROR_MORE_DATA: error = EPIPE; break;
|
||||
case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
|
||||
case ERROR_NOACCESS: error = EFAULT; break;
|
||||
case ERROR_NONE_MAPPED: error = EINVAL; break;
|
||||
case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
|
||||
case ERROR_NOT_READY: error = EAGAIN; break;
|
||||
case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
|
||||
case ERROR_NO_DATA: error = EPIPE; break;
|
||||
case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
|
||||
case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
|
||||
case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
|
||||
case ERROR_OPEN_FAILED: error = EIO; break;
|
||||
case ERROR_OPEN_FILES: error = EBUSY; break;
|
||||
case ERROR_OPERATION_ABORTED: error = EINTR; break;
|
||||
case ERROR_OUTOFMEMORY: error = ENOMEM; break;
|
||||
case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
|
||||
case ERROR_PATH_BUSY: error = EBUSY; break;
|
||||
case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
|
||||
case ERROR_PIPE_BUSY: error = EBUSY; break;
|
||||
case ERROR_PIPE_CONNECTED: error = EPIPE; break;
|
||||
case ERROR_PIPE_LISTENING: error = EPIPE; break;
|
||||
case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
|
||||
case ERROR_READ_FAULT: error = EIO; break;
|
||||
case ERROR_SEEK: error = EIO; break;
|
||||
case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
|
||||
case ERROR_SHARING_VIOLATION: error = EACCES; break;
|
||||
case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
|
||||
case ERROR_SUCCESS: error = 0; break;
|
||||
case ERROR_SWAPERROR: error = ENOENT; break;
|
||||
case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
|
||||
case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
|
||||
case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
|
||||
case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
|
||||
case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
|
||||
case ERROR_WRITE_FAULT: error = EIO; break;
|
||||
case ERROR_WRITE_PROTECT: error = EROFS; break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// from msys2 mingw-packages-dev patches
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static DWORD __map_mmap_prot_page(const int prot)
|
||||
{
|
||||
DWORD protect = 0;
|
||||
|
||||
if (prot == PROT_NONE)
|
||||
return protect;
|
||||
|
||||
if ((prot & PROT_EXEC) != 0)
|
||||
{
|
||||
protect = ((prot & PROT_WRITE) != 0) ?
|
||||
PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
protect = ((prot & PROT_WRITE) != 0) ?
|
||||
PAGE_READWRITE : PAGE_READONLY;
|
||||
}
|
||||
|
||||
return protect;
|
||||
}
|
||||
|
||||
static DWORD __map_mmap_prot_file(const int prot)
|
||||
{
|
||||
DWORD desiredAccess = 0;
|
||||
|
||||
if (prot == PROT_NONE)
|
||||
return desiredAccess;
|
||||
|
||||
if ((prot & PROT_READ) != 0)
|
||||
desiredAccess |= FILE_MAP_READ;
|
||||
if ((prot & PROT_WRITE) != 0)
|
||||
desiredAccess |= FILE_MAP_WRITE;
|
||||
if ((prot & PROT_EXEC) != 0)
|
||||
desiredAccess |= FILE_MAP_EXECUTE;
|
||||
|
||||
return desiredAccess;
|
||||
}
|
||||
|
||||
void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
|
||||
{
|
||||
HANDLE fm, h;
|
||||
|
||||
void * map = MAP_FAILED;
|
||||
|
||||
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
|
||||
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
|
||||
const DWORD protect = __map_mmap_prot_page(prot);
|
||||
const DWORD desiredAccess = __map_mmap_prot_file(prot);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (len == 0
|
||||
/* Usupported protection combinations */
|
||||
|| prot == PROT_EXEC)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
if ((flags & MAP_ANON) == 0)
|
||||
{
|
||||
h = (HANDLE)_get_osfhandle(fildes);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
else h = INVALID_HANDLE_VALUE;
|
||||
|
||||
fm = CreateFileMapping(h, NULL, protect, 0, len, NULL);
|
||||
|
||||
if (fm == NULL)
|
||||
{
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr);
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
|
||||
CloseHandle(fm);
|
||||
|
||||
if (map == NULL)
|
||||
return MAP_FAILED;
|
||||
|
||||
if ((flags & MAP_FIXED) != 0 && map != addr)
|
||||
{
|
||||
UnmapViewOfFile(map);
|
||||
errno = EEXIST;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
int munmap(void *addr, size_t len)
|
||||
{
|
||||
if (UnmapViewOfFile(addr))
|
||||
return 0;
|
||||
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int msync(void *addr, size_t len, int flags)
|
||||
{
|
||||
if (FlushViewOfFile(addr, len))
|
||||
return 0;
|
||||
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// vere uses kill() only to kill lockfile owner with SIGTERM or SIGKILL
|
||||
// Windows does not have signals, so I handle SIGKILL as TerminateProcess()
|
||||
// and return an error in all other cases
|
||||
int kill(pid_t pid, int sig)
|
||||
{
|
||||
if (pid > 0 && sig == SIGKILL) {
|
||||
HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
|
||||
if (TerminateProcess(h, -1)) {
|
||||
CloseHandle(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// libgcc built for mingw has included an implementation of mprotect
|
||||
// via VirtualProtect since olden days, but it takes int rather than size_t
|
||||
// and therefore fails or does unexpected things for >2GB blocks on 64-bit
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libgcc/libgcc2.c
|
||||
int mprotect (void *addr, size_t len, int prot)
|
||||
{
|
||||
DWORD np, op;
|
||||
|
||||
if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
np = PAGE_EXECUTE_READWRITE;
|
||||
else if (prot == (PROT_READ | PROT_EXEC))
|
||||
np = PAGE_EXECUTE_READ;
|
||||
else if (prot == (PROT_EXEC))
|
||||
np = PAGE_EXECUTE;
|
||||
else if (prot == (PROT_READ | PROT_WRITE))
|
||||
np = PAGE_READWRITE;
|
||||
else if (prot == (PROT_READ))
|
||||
np = PAGE_READONLY;
|
||||
else if (prot == 0)
|
||||
np = PAGE_NOACCESS;
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (VirtualProtect (addr, len, np, &op))
|
||||
return 0;
|
||||
|
||||
// NB: return code of ntdll!RtlGetLastNtStatus() is useful
|
||||
// for diagnosing obscure VirtualProtect failures
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int utimes(const char *path, const struct timeval times[2])
|
||||
{
|
||||
struct _utimbuf utb = {.actime = times[0].tv_sec, .modtime = times[1].tv_sec};
|
||||
return _utime(path, &utb);
|
||||
}
|
||||
|
||||
int fdatasync(int fildes)
|
||||
{
|
||||
HANDLE h = (HANDLE)_get_osfhandle(fildes);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FlushFileBuffers(h))
|
||||
{
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
intmax_t mdb_get_filesize(HANDLE han_u)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
GetFileSizeEx(han_u, &li);
|
||||
return li.QuadPart;
|
||||
}
|
||||
|
||||
char *realpath(const char *path, char *resolved_path)
|
||||
{
|
||||
// TODO
|
||||
return strdup(path);
|
||||
}
|
18
pkg/urbit/compat/mingw/compat.h
Normal file
18
pkg/urbit/compat/mingw/compat.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _MINGW_IO_H
|
||||
#define _MINGW_IO_H
|
||||
|
||||
#define mkdir(A, B) mkdir(A)
|
||||
|
||||
char *realpath(const char *path, char *resolved_path);
|
||||
int fdatasync(int fd);
|
||||
int utimes(const char *path, const struct timeval times[2]);
|
||||
|
||||
int kill(pid_t pid, int signum);
|
||||
|
||||
#define SIGUSR1 10
|
||||
#define SIGALRM 14
|
||||
#define SIGVTALRM 26
|
||||
#define SIGSTK 31
|
||||
#define SIG_COUNT 32
|
||||
|
||||
#endif//_MINGW_IO_H
|
17
pkg/urbit/compat/mingw/compat.mk
Normal file
17
pkg/urbit/compat/mingw/compat.mk
Normal file
@ -0,0 +1,17 @@
|
||||
# increase default thread stack size and link Windows implibs
|
||||
LDFLAGS := $(LDFLAGS) -static -Wl,--stack,67108864 -lbcrypt -lntdll -lws2_32
|
||||
# libcurl
|
||||
CFLAGS := $(CFLAGS) -DCURL_STATICLIB
|
||||
LDFLAGS := $(LDFLAGS) -lzstd -lcrypt32
|
||||
# libh2o
|
||||
CFLAGS := $(CFLAGS) -DH2O_NO_UNIX_SOCKETS
|
||||
# libuv
|
||||
LDFLAGS := $(LDFLAGS) -luserenv -liphlpapi -lpsapi
|
||||
# secp256k1, due to _FORTIFY_SOURCE
|
||||
LDFLAGS := $(LDFLAGS) -lssp
|
||||
|
||||
ifdef debug
|
||||
CFLAGS := $(CFLAGS) -O0 -g
|
||||
else
|
||||
CFLAGS := $(CFLAGS) -O3 -g
|
||||
endif
|
7
pkg/urbit/compat/mingw/ctrlc.c
Normal file
7
pkg/urbit/compat/mingw/ctrlc.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <signal.h>
|
||||
|
||||
// initialize msvcrt signals early, otherwise Ctrl-C does nothing
|
||||
static void __attribute__ ((constructor)) _init_crt_signals()
|
||||
{
|
||||
signal(SIGINT, SIG_DFL);
|
||||
}
|
116
pkg/urbit/compat/mingw/daemon.c
Normal file
116
pkg/urbit/compat/mingw/daemon.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _dup_std_handle(): creates an inheritable duplicate of a standard handle.
|
||||
*/
|
||||
static BOOL
|
||||
_dup_std_handle(HANDLE* new_u, DWORD typ_u)
|
||||
{
|
||||
DWORD dum_u;
|
||||
HANDLE han_u = GetStdHandle(typ_u);
|
||||
BOOL con_u = GetConsoleMode(han_u, &dum_u);
|
||||
if ( con_u ) {
|
||||
han_u = (HANDLE)_get_osfhandle(open(c3_dev_null, O_RDWR, 0));
|
||||
}
|
||||
|
||||
if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) {
|
||||
fprintf(stderr, "vere: DuplicateHandle(%d): %d\r\n", typ_u, GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return con_u;
|
||||
}
|
||||
|
||||
/* _on_boot_completed_cb: invoked when the ship has finished booting.
|
||||
*/
|
||||
static void _on_boot_completed_cb() {
|
||||
HANDLE hin_u = GetStdHandle(STD_INPUT_HANDLE);
|
||||
SetEvent(hin_u);
|
||||
CloseHandle(hin_u);
|
||||
}
|
||||
|
||||
/* u3_daemon_init(): platform-specific daemon mode initialization.
|
||||
*/
|
||||
void
|
||||
u3_daemon_init()
|
||||
{
|
||||
// detect if this process is the child daemon process
|
||||
//
|
||||
if ( ResetEvent(GetStdHandle(STD_INPUT_HANDLE)) ) {
|
||||
u3_Host.bot_f = _on_boot_completed_cb;
|
||||
return;
|
||||
}
|
||||
|
||||
STARTUPINFOW psi_u;
|
||||
ZeroMemory(&psi_u, sizeof(psi_u));
|
||||
psi_u.cb = sizeof(psi_u);
|
||||
psi_u.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
// duplicate standard output and error handles for the child process,
|
||||
// replacing any raw console handles with handles to /dev/null
|
||||
// print a warning if raw console output detected
|
||||
//
|
||||
// On Windows, console handles become invalid once the console is
|
||||
// detached. This will cause urbit terminal output to fail. libuv
|
||||
// provides no way of changing the handle of an open uv_pipe_handle,
|
||||
// and Windows has no equivalent of dup2() for handles, so I cannot
|
||||
// substitute a /dev/null handle once the terminal is initialized.
|
||||
// It is possible to create an anonymous pipe and have the child
|
||||
// process take over its drain end after it signals that the ship
|
||||
// has booted, but -d is intended for background operation anyway
|
||||
// and does not seem to warrant the added complexity.
|
||||
//
|
||||
if ( _dup_std_handle(&psi_u.hStdOutput, STD_OUTPUT_HANDLE) |
|
||||
_dup_std_handle(&psi_u.hStdError, STD_ERROR_HANDLE) )
|
||||
{
|
||||
fprintf(stderr, "vere: -d used from a Windows console without redirection\r\n"
|
||||
" no output from the daemon process will be visible\r\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
// create an event for the child process to signal
|
||||
// the parent that the ship has finished booting
|
||||
// pass the handle as "stdin" (otherwise unused with -d)
|
||||
//
|
||||
SECURITY_ATTRIBUTES sa_u = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||
if ( !(psi_u.hStdInput = CreateEvent(&sa_u, TRUE, FALSE, NULL)) ) {
|
||||
fprintf(stderr, "vere: CreateEvent: %d\r\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// create the child process with the same command line as parent
|
||||
// it will start, re-parse the command line, and call u3_daemon_init
|
||||
//
|
||||
PROCESS_INFORMATION ppi_u;
|
||||
if ( !CreateProcessW(NULL, _wcsdup(GetCommandLineW()), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &psi_u, &ppi_u) ) {
|
||||
fprintf(stderr, "vere: CreateProcess: %d\r\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CloseHandle(ppi_u.hThread);
|
||||
|
||||
// wait for the child process to exit or to signal the event
|
||||
//
|
||||
DWORD exi_u;
|
||||
HANDLE han_u[2] = {ppi_u.hProcess, psi_u.hStdInput};
|
||||
switch ( WaitForMultipleObjects(2, han_u, FALSE, INFINITE) ) {
|
||||
case WAIT_OBJECT_0:
|
||||
// the child process exited prematurely, propagate its exit code
|
||||
//
|
||||
if ( GetExitCodeProcess(ppi_u.hProcess, &exi_u) ) {
|
||||
exit(exi_u);
|
||||
}
|
||||
|
||||
fprintf(stderr, "vere: GetExitCodeProcess: %d\r\n", GetLastError());
|
||||
exit(1);
|
||||
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
// the child process has finished booting, exit normally
|
||||
//
|
||||
exit(0);
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vere: WaitForMultipleObjects: %d\r\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
1834
pkg/urbit/compat/mingw/h2o.patch
Normal file
1834
pkg/urbit/compat/mingw/h2o.patch
Normal file
File diff suppressed because it is too large
Load Diff
74
pkg/urbit/compat/mingw/lmdb.patch
Normal file
74
pkg/urbit/compat/mingw/lmdb.patch
Normal file
@ -0,0 +1,74 @@
|
||||
diff --git a/mdb.c b/mdb.c
|
||||
--- a/mdb.c
|
||||
+++ b/mdb.c
|
||||
@@ -1707,28 +1707,27 @@ static char *const mdb_errstr[] = {
|
||||
"MDB_PROBLEM: Unexpected problem - txn should abort",
|
||||
};
|
||||
|
||||
-char *
|
||||
-mdb_strerror(int err)
|
||||
+void
|
||||
+mdb_logerror(FILE* f, int err, const char* fmt, ...)
|
||||
{
|
||||
-#ifdef _WIN32
|
||||
- /** HACK: pad 4KB on stack over the buf. Return system msgs in buf.
|
||||
- * This works as long as no function between the call to mdb_strerror
|
||||
- * and the actual use of the message uses more than 4K of stack.
|
||||
- */
|
||||
-#define MSGSIZE 1024
|
||||
-#define PADSIZE 4096
|
||||
- char buf[MSGSIZE+PADSIZE], *ptr = buf;
|
||||
-#endif
|
||||
+ va_list ap;
|
||||
+ va_start(ap, fmt);
|
||||
+ vfprintf(f, fmt, ap);
|
||||
+ va_end(ap);
|
||||
+
|
||||
int i;
|
||||
if (!err)
|
||||
- return ("Successful return: 0");
|
||||
+ {
|
||||
+ fprintf(stderr, ": %s\r\n", "Successful return: 0");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) {
|
||||
i = err - MDB_KEYEXIST;
|
||||
- return mdb_errstr[i];
|
||||
+ fprintf(stderr, ": %s\r\n", mdb_errstr[i]);
|
||||
+ return;
|
||||
}
|
||||
|
||||
-#ifdef _WIN32
|
||||
/* These are the C-runtime error codes we use. The comment indicates
|
||||
* their numeric value, and the Win32 error they would correspond to
|
||||
* if the error actually came from a Win32 API. A major mess, we should
|
||||
@@ -1742,18 +1741,20 @@ mdb_strerror(int err)
|
||||
case EBUSY: /* 16, CURRENT_DIRECTORY */
|
||||
case EINVAL: /* 22, BAD_COMMAND */
|
||||
case ENOSPC: /* 28, OUT_OF_PAPER */
|
||||
- return strerror(err);
|
||||
+ fprintf(stderr, ": %s\r\n", strerror(err));
|
||||
default:
|
||||
;
|
||||
}
|
||||
- buf[0] = 0;
|
||||
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
+ LPSTR ptr;
|
||||
+ if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
- NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE);
|
||||
- return ptr;
|
||||
-#else
|
||||
- return strerror(err);
|
||||
-#endif
|
||||
+ NULL, err, 0, (LPSTR)&ptr, sizeof (LPSTR), NULL))
|
||||
+ {
|
||||
+ fprintf(stderr, ": %s\r\n", ptr);
|
||||
+ LocalFree(ptr);
|
||||
+ } else
|
||||
+ fprintf(stderr, ": <%d>\r\n", err);
|
||||
}
|
||||
|
||||
/** assert(3) variant in cursor context */
|
26
pkg/urbit/compat/mingw/mman.h
Normal file
26
pkg/urbit/compat/mingw/mman.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _SYS_MMAN_H
|
||||
#define _SYS_MMAN_H
|
||||
|
||||
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
int munmap(void *addr, size_t length);
|
||||
int msync(void *addr, size_t length, int flags);
|
||||
int mprotect(void *addr, size_t len, int prot);
|
||||
|
||||
#define PROT_NONE 0x00 /* No access. */
|
||||
#define PROT_READ 0x01 /* Pages can be read. */
|
||||
#define PROT_WRITE 0x02 /* Pages can be written. */
|
||||
#define PROT_EXEC 0x04 /* Pages can be executed. */
|
||||
|
||||
#define MAP_FILE 0x0001 /* Mapped from a file or device. */
|
||||
#define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */
|
||||
#define MAP_TYPE 0x000f /* Mask for type field. */
|
||||
#define MAP_SHARED 0x0010 /* Share changes. */
|
||||
#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */
|
||||
#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
|
||||
#define MS_ASYNC 1 /* Sync memory asynchronously. */
|
||||
#define MS_SYNC 0 /* Synchronous memory sync. */
|
||||
#define MS_INVALIDATE 2 /* Invalidate the caches. */
|
||||
|
||||
#endif//_SYS_MMAN_H
|
13
pkg/urbit/compat/mingw/murmur3.patch
Normal file
13
pkg/urbit/compat/mingw/murmur3.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/makefile b/makefile
|
||||
--- a/makefile
|
||||
+++ b/makefile
|
||||
@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h
|
||||
$(CC) -fPIC -O3 -c murmur3.c
|
||||
$(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so
|
||||
|
||||
+static: murmur3.c murmur3.h
|
||||
+ $(CC) -fPIC -O3 -c murmur3.c
|
||||
+ $(AR) rcs libmurmur3.a murmur3.o
|
||||
+
|
||||
clean:
|
||||
rm -rf example *.o *.so
|
152
pkg/urbit/compat/mingw/ptty.c
Normal file
152
pkg/urbit/compat/mingw/ptty.c
Normal file
@ -0,0 +1,152 @@
|
||||
/* compat/mingw/ptty.c
|
||||
**
|
||||
*/
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
#include <winternl.h>
|
||||
|
||||
/* _ptty_get_type(): detects tty type.
|
||||
*/
|
||||
static DWORD
|
||||
_ptty_get_type(int fd)
|
||||
{
|
||||
HANDLE h = (HANDLE)_get_osfhandle(fd);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
|
||||
DWORD t = GetFileType(h);
|
||||
if (t != FILE_TYPE_PIPE)
|
||||
return t ;
|
||||
|
||||
// https://github.com/fusesource/jansi-native/commit/461068c67a38647d2890e96250636fc0117074f5
|
||||
ULONG result;
|
||||
BYTE buffer[1024];
|
||||
POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer;
|
||||
PWSTR name;
|
||||
|
||||
/* get pipe name */
|
||||
if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation, buffer, sizeof(buffer) - sizeof(WCHAR), &result)))
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
|
||||
name = nameinfo->Name.Buffer;
|
||||
name[nameinfo->Name.Length] = 0;
|
||||
|
||||
// check for popular terminal emulators
|
||||
// that use named pipes to communicate with subprocesses
|
||||
if (wcsstr(name, L"\\ConEmu") ||
|
||||
(wcsstr(name, L"msys-") || wcsstr(name, L"cygwin-")) && wcsstr(name, L"-pty"))
|
||||
return FILE_TYPE_PIPE;
|
||||
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* _ttyf_nop(): stub function.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_nop(u3_utty* uty_u)
|
||||
{
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_start_raw_input(): ends raw input on the tty.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_set_normal(u3_utty* uty_u)
|
||||
{
|
||||
c3_i e;
|
||||
if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_NORMAL)) ) {
|
||||
fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_NORMAL) -> %d\r\n", e);
|
||||
return c3n;
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_start_raw_input(): sets the tty to raw input.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_set_raw(u3_utty* uty_u)
|
||||
{
|
||||
c3_i e;
|
||||
if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_RAW)) ) {
|
||||
fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_RAW) -> %d\r\n", e);
|
||||
return c3n;
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_get_winsize(): gets the tty window size.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l)
|
||||
{
|
||||
c3_i col_i, row_i;
|
||||
if ( 0 != uv_tty_get_winsize(&uty_u->pop_u.tty_u, &col_i, &row_i) ) {
|
||||
return c3n;
|
||||
}
|
||||
|
||||
*col_l = col_i;
|
||||
*row_l = row_i;
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_get_winsize(): gets the tty window size.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_nop_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l)
|
||||
{
|
||||
return c3n;
|
||||
}
|
||||
|
||||
/* u3_ptty_init(): initialize platform-specific tty.
|
||||
*/
|
||||
u3_utty*
|
||||
u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c)
|
||||
{
|
||||
DWORD pip_l = _ptty_get_type(0);
|
||||
DWORD pop_l = _ptty_get_type(1);
|
||||
if ( pip_l == FILE_TYPE_UNKNOWN || pop_l == FILE_TYPE_UNKNOWN) {
|
||||
*err_c = "not a tty";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( pip_l != pop_l ) {
|
||||
*err_c = "partly redirected";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c3_i e;
|
||||
u3_utty* uty_u = c3_calloc(sizeof(u3_utty));
|
||||
if ( pip_l == FILE_TYPE_CHAR ) {
|
||||
if ( 0 == (e = uv_tty_init(lup_u, &uty_u->pin_u.tty_u, 0, 0)) &&
|
||||
0 == (e = uv_tty_init(lup_u, &uty_u->pop_u.tty_u, 1, 0)) )
|
||||
{
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
uty_u->sta_f = _ttyf_set_raw;
|
||||
uty_u->sto_f = _ttyf_set_normal;
|
||||
uty_u->wsz_f = _ttyf_get_winsize;
|
||||
}
|
||||
} else {
|
||||
if ( 0 == (e = uv_pipe_init(lup_u, &uty_u->pin_u.pip_u, 0)) &&
|
||||
0 == (e = uv_pipe_init(lup_u, &uty_u->pop_u.pip_u, 0)) &&
|
||||
0 == (e = uv_pipe_open(&uty_u->pin_u.pip_u, 0)) &&
|
||||
0 == (e = uv_pipe_open(&uty_u->pop_u.pip_u, 1)) )
|
||||
{
|
||||
fprintf(stderr, "vere: running interactive in a terminal emulator is experimental\r\n"
|
||||
" use -t to disable interactivity or use native Windows console\r\n") ;
|
||||
uty_u->sta_f = _ttyf_nop;
|
||||
uty_u->sto_f = _ttyf_nop;
|
||||
uty_u->wsz_f = _ttyf_nop_winsize;
|
||||
}
|
||||
}
|
||||
|
||||
if ( e ) {
|
||||
*err_c = uv_strerror(e);
|
||||
c3_free(uty_u);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uty_u->fid_i = 1;
|
||||
uty_u->hij_f = _ttyf_nop;
|
||||
uty_u->loj_f = _ttyf_nop;
|
||||
return uty_u;
|
||||
}
|
167
pkg/urbit/compat/mingw/rsignal.c
Normal file
167
pkg/urbit/compat/mingw/rsignal.c
Normal file
@ -0,0 +1,167 @@
|
||||
#include "all.h"
|
||||
#include "rsignal.h"
|
||||
#include <windows.h>
|
||||
|
||||
int err_win_to_posix(DWORD winerr);
|
||||
|
||||
// The current implementation of rsignal_ is single-threaded,
|
||||
// but it can be extended to multi-threaded by replacing these
|
||||
// static variables with a thread id-based hash map.
|
||||
//
|
||||
static __p_sig_fn_t _fns[SIG_COUNT];
|
||||
static volatile DWORD _tid;
|
||||
static HANDLE _hvt;
|
||||
|
||||
void rsignal_install_handler(int sig, __p_sig_fn_t fn)
|
||||
{
|
||||
if (sig < 0 || sig >= SIG_COUNT)
|
||||
return;
|
||||
|
||||
DWORD newtid = GetCurrentThreadId();
|
||||
DWORD oldtid = InterlockedExchange(&_tid, newtid);
|
||||
if (oldtid != 0 && oldtid != newtid) {
|
||||
fprintf(stderr, "\r\nrsignal_install_handler: %u -> %u\r\n", oldtid, newtid);
|
||||
return;
|
||||
}
|
||||
|
||||
__p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], fn);
|
||||
if (fn != 0 && oldfn != 0 && oldfn != fn) {
|
||||
fprintf(stderr, "\r\nrsignal_install_handler: %p -> %p\r\n", oldfn, fn);
|
||||
}
|
||||
}
|
||||
|
||||
void rsignal_deinstall_handler(int sig)
|
||||
{
|
||||
rsignal_install_handler(sig, 0);
|
||||
}
|
||||
|
||||
void rsignal_raise(int sig)
|
||||
{
|
||||
if (sig < 0 || sig >= SIG_COUNT)
|
||||
return;
|
||||
|
||||
__p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], 0);
|
||||
if (oldfn == 0)
|
||||
return;
|
||||
|
||||
if (_tid == GetCurrentThreadId()) {
|
||||
oldfn(sig);
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, _tid);
|
||||
if (!hthread) {
|
||||
fprintf(stderr, "\r\nrsignal_raise: OpenThread(%u): %d\r\n", _tid, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (SuspendThread(hthread) < 0) {
|
||||
fprintf(stderr, "\r\nrsignal_raise: SuspendThread(%u): %d\r\n", _tid, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
oldfn(sig);
|
||||
|
||||
if (!ResumeThread(hthread)) {
|
||||
fprintf(stderr, "\r\nrsignal_raise: ResumeThread(%u): %d\r\n", _tid, GetLastError());
|
||||
|
||||
// abort because the main thread is stuck
|
||||
abort();
|
||||
}
|
||||
|
||||
cleanup:
|
||||
CloseHandle(hthread);
|
||||
}
|
||||
|
||||
static void _rsignal_vt_cb(PVOID param, BOOLEAN timedOut)
|
||||
{
|
||||
rsignal_raise(SIGVTALRM);
|
||||
}
|
||||
|
||||
int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out)
|
||||
{
|
||||
if (in == 0) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type != ITIMER_VIRTUAL || out != 0) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_hvt != NULL) {
|
||||
DeleteTimerQueueTimer(NULL, _hvt, NULL);
|
||||
_hvt = NULL;
|
||||
}
|
||||
|
||||
if (timerisset(&in->it_value) && !CreateTimerQueueTimer(&_hvt, NULL, _rsignal_vt_cb, NULL,
|
||||
in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000,
|
||||
in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000, 0))
|
||||
{
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// direct import from ntdll.dll
|
||||
extern DWORD64 __imp_KiUserExceptionDispatcher;
|
||||
|
||||
static void _rsignal_longjmp(intptr_t* builtin_jb)
|
||||
{
|
||||
__builtin_longjmp(builtin_jb, 1);
|
||||
}
|
||||
|
||||
void rsignal_post_longjmp(DWORD tid, intptr_t* builtin_jb)
|
||||
{
|
||||
HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
|
||||
if (!hthread) {
|
||||
fprintf(stderr, "\r\nrsignal: OpenThread(%u): %d\r\n", tid, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
if (!GetThreadContext(hthread, &context)) {
|
||||
fprintf(stderr, "\r\nrsignal: GetThreadContext(%u): %d\r\n", tid, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// see if the thread is currently handling a structured exception
|
||||
// if so, let the handler (usually the libsigsegv handler) finish
|
||||
// and set up the the signal to run at the exception resume point
|
||||
// otherwise, passing a parameter to fn is completely unreliable
|
||||
//
|
||||
DWORD64 kibase;
|
||||
PRUNTIME_FUNCTION ki = RtlLookupFunctionEntry(__imp_KiUserExceptionDispatcher, &kibase, NULL);
|
||||
CONTEXT c = context;
|
||||
while (1)
|
||||
{
|
||||
DWORD64 base, frame;
|
||||
PRUNTIME_FUNCTION f = RtlLookupFunctionEntry(c.Rip, &base, NULL);
|
||||
if (!f) break;
|
||||
if (f == ki)
|
||||
{
|
||||
// KiUserExceptionDispatcher has a "bare" frame
|
||||
// with $rsp pointing to the CONTEXT structure
|
||||
//
|
||||
((PCONTEXT)c.Rsp)->Rip = (DWORD64)_rsignal_longjmp;
|
||||
((PCONTEXT)c.Rsp)->Rcx = (DWORD64)builtin_jb;
|
||||
goto cleanup;
|
||||
}
|
||||
PVOID handler_data;
|
||||
RtlVirtualUnwind(0, base, c.Rip, f, &c, &handler_data, &frame, NULL);
|
||||
}
|
||||
|
||||
context.Rip = (DWORD64)_rsignal_longjmp;
|
||||
context.Rcx = (DWORD64)builtin_jb;
|
||||
if (!SetThreadContext(hthread, &context)) {
|
||||
fprintf(stderr, "\r\nrsignal: SetThreadContext(%u): %d\r\n", tid, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
CloseHandle(hthread);
|
||||
}
|
24
pkg/urbit/compat/mingw/rsignal.h
Normal file
24
pkg/urbit/compat/mingw/rsignal.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef _RSIGNAL_H
|
||||
#define _RSIGNAL_H
|
||||
|
||||
typedef struct {
|
||||
jmp_buf jb;
|
||||
unsigned long tid;
|
||||
} rsignal_jmpbuf;
|
||||
|
||||
#define rsignal_setjmp(buf) (buf.tid = GetCurrentThreadId(), setjmp(buf.jb))
|
||||
#define rsignal_longjmp(buf, val) if (buf.tid != GetCurrentThreadId()) {buf.jb.retval = (val); rsignal_post_longjmp(buf.tid, buf.jb.buffer);} else longjmp(buf.jb, val)
|
||||
|
||||
void rsignal_raise(int sig);
|
||||
void rsignal_install_handler(int sig, __p_sig_fn_t fn);
|
||||
void rsignal_deinstall_handler(int sig);
|
||||
void rsignal_post_longjmp(unsigned long tid, intptr_t* builtin_jb);
|
||||
|
||||
#define ITIMER_VIRTUAL 1
|
||||
struct itimerval {
|
||||
struct timeval it_value, it_interval;
|
||||
};
|
||||
|
||||
int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out);
|
||||
|
||||
#endif//_RSIGNAL_H
|
25
pkg/urbit/compat/mingw/seh_handler.c
Normal file
25
pkg/urbit/compat/mingw/seh_handler.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "all.h"
|
||||
#include "rsignal.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
/* _mingw_exception_filter: replaces libsigsegv on MingW
|
||||
*/
|
||||
EXCEPTION_DISPOSITION _mingw_exception_filter(
|
||||
IN PEXCEPTION_RECORD ExceptionRecord,
|
||||
IN ULONG64 EstablisherFrame,
|
||||
IN OUT PCONTEXT ContextRecord,
|
||||
IN OUT PDISPATCHER_CONTEXT DispatcherContext)
|
||||
{
|
||||
if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
|
||||
ExceptionRecord->ExceptionInformation[0] == 1 &&
|
||||
u3e_fault((void*)ExceptionRecord->ExceptionInformation[1], 1))
|
||||
{
|
||||
return ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
|
||||
rsignal_raise(SIGSTK);
|
||||
}
|
||||
|
||||
return ExceptionContinueSearch;
|
||||
}
|
65
pkg/urbit/compat/mingw/seh_handler_decorator.cc
Normal file
65
pkg/urbit/compat/mingw/seh_handler_decorator.cc
Normal file
@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
enum { INIT, CPAR, DQ, DQS, SQ, SQS };
|
||||
char line[1 << 16];
|
||||
|
||||
/* seh_handler_decorator: registers u3_exception_handler for all functions in given source file
|
||||
*/
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
int c, state = INIT, curly = 0, emit = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), stdin))
|
||||
{
|
||||
if (line[0] == '#')
|
||||
{
|
||||
emit = !!strstr(line, argv[1]);
|
||||
fputs(line, stdout);
|
||||
}
|
||||
else
|
||||
for (int i = 0; line[i]; i++)
|
||||
{
|
||||
switch (state) {
|
||||
case INIT:
|
||||
case CPAR:
|
||||
switch (line[i]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\f': break;
|
||||
case '{': curly++; if (emit && curly == 1 && state == CPAR) goto emit_handler; goto reset;
|
||||
case '}': curly--; goto reset;
|
||||
case '"': state = DQ; break;
|
||||
case '\'': state = SQ; break;
|
||||
case ')': state = CPAR; break;
|
||||
reset:
|
||||
default: state = INIT; break;
|
||||
} break;
|
||||
case DQ:
|
||||
switch (line[i]) {
|
||||
case '\\': state = DQS; break;
|
||||
case '"': state = INIT; break;
|
||||
} break;
|
||||
case DQS: state = DQ; break;
|
||||
case SQ:
|
||||
switch (line[i]) {
|
||||
case '\\': state = SQS; break;
|
||||
case '\'': state = INIT; break;
|
||||
} break;
|
||||
case SQS: state = SQ; break;
|
||||
}
|
||||
fputc(line[i], stdout);
|
||||
continue;
|
||||
emit_handler:
|
||||
fputs("{__asm__(\".seh_handler _mingw_exception_filter,@except\\n\");", stdout);
|
||||
state = INIT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
24
pkg/urbit/compat/mingw/seh_handler_decorator.mk
Normal file
24
pkg/urbit/compat/mingw/seh_handler_decorator.mk
Normal file
@ -0,0 +1,24 @@
|
||||
# This include file injects a step that transforms vere C source to register
|
||||
# a SEH exception handler for each function that is declared in a .c file.
|
||||
# It inserts a .seh_handler directive into each function body with __asm__.
|
||||
# This directive affects the x64 unwind tables (.pdata and .xdata sections)
|
||||
# emitted by the compiler.
|
||||
#
|
||||
# See gas/config/obj-coff-seh.h in binutils source for .seh_handler, and
|
||||
# https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
|
||||
# for a description of how stack unwinding and SEH work in x64 Windows.
|
||||
#
|
||||
# When this file sets CCEXTRA, the first invocation of $(CC) in Makefile
|
||||
# writes preprocessor output to stdout (-E -o -), which is piped to a simple
|
||||
# parser that inserts __asm__ statements to each function in the .c file
|
||||
# being compiled. The second invocation of $(CC) reads transformed source
|
||||
# from stdin (-x cpp-output -). $< argument to $(sehdexe) tells the parser
|
||||
# which .c file is being compiled.
|
||||
|
||||
sehdexe := build/seh_handler_decorator.exe
|
||||
CCDEPS := $(CCDEPS) $(sehdexe)
|
||||
CCEXTRA = -E -o -|$(sehdexe) $<|$(CC) $(CFLAGS) -x cpp-output -
|
||||
|
||||
$(sehdexe): compat/mingw/seh_handler_decorator.cc
|
||||
@mkdir -p ./build
|
||||
@$(CC) $< -o $@
|
15
pkg/urbit/compat/mingw/setjmp.h
Normal file
15
pkg/urbit/compat/mingw/setjmp.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _MINGW_SETJMP_H
|
||||
#define _MINGW_SETJMP_H
|
||||
|
||||
// msvcrt setjmp/longjmp are broken on 64-bit systems, use gcc builtins
|
||||
typedef struct jmp_buf {
|
||||
intptr_t buffer[5];
|
||||
int retval;
|
||||
} jmp_buf;
|
||||
|
||||
#define _setjmp setjmp
|
||||
#define _longjmp longjmp
|
||||
#define longjmp(buf, val) {buf.retval = (val); __builtin_longjmp(buf.buffer, 1);}
|
||||
#define setjmp(buf) (__builtin_setjmp(buf.buffer) ? (buf.retval) : 0)
|
||||
|
||||
#endif//_MINGW_SETJMP_H
|
36
pkg/urbit/compat/mingw/softfloat3.patch
Normal file
36
pkg/urbit/compat/mingw/softfloat3.patch
Normal file
@ -0,0 +1,36 @@
|
||||
diff --git a/build/Win64-MinGW-w64/Makefile b/build/Win64-MinGW-w64/Makefile
|
||||
--- a/build/Win64-MinGW-w64/Makefile
|
||||
+++ b/build/Win64-MinGW-w64/Makefile
|
||||
@@ -46,7 +46,8 @@ C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include
|
||||
COMPILE_C = \
|
||||
x86_64-w64-mingw32-gcc -c -Werror-implicit-function-declaration \
|
||||
-DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@
|
||||
-MAKELIB = x86_64-w64-mingw32-ar crs $@
|
||||
+MAKELIB = x86_64-w64-mingw32-gcc-ar crs $@
|
||||
+LIBNAME = libsoftfloat3
|
||||
|
||||
OBJ = .o
|
||||
LIB = .a
|
||||
@@ -54,7 +55,7 @@ LIB = .a
|
||||
OTHER_HEADERS = $(SOURCE_DIR)/include/opts-GCC.h
|
||||
|
||||
.PHONY: all
|
||||
-all: softfloat$(LIB)
|
||||
+all: $(LIBNAME)$(LIB)
|
||||
|
||||
OBJS_PRIMITIVES = \
|
||||
s_eq128$(OBJ) \
|
||||
@@ -380,11 +381,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c
|
||||
$(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c
|
||||
$(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c
|
||||
|
||||
-softfloat$(LIB): $(OBJS_ALL)
|
||||
+$(LIBNAME)$(LIB): $(OBJS_ALL)
|
||||
$(DELETE) $@
|
||||
$(MAKELIB) $^
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
- $(DELETE) $(OBJS_ALL) softfloat$(LIB)
|
||||
+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB)
|
||||
|
38
pkg/urbit/compat/mingw/uv.patch
Normal file
38
pkg/urbit/compat/mingw/uv.patch
Normal file
@ -0,0 +1,38 @@
|
||||
diff --git a/src/win/pipe.c b/src/win/pipe.c
|
||||
index 0f2bb869b..f81245ec6 100644
|
||||
--- a/src/win/pipe.c
|
||||
+++ b/src/win/pipe.c
|
||||
@@ -270,6 +270,12 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
|
||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||
err = GetLastError();
|
||||
+ if ((err == ERROR_INVALID_FUNCTION || err == ERROR_INVALID_PARAMETER) && (duplex_flags & UV_HANDLE_WRITABLE)) {
|
||||
+ /*
|
||||
+ * it's not a pipe, but simple writes should be fine
|
||||
+ * let's trust callers to know what they're doing
|
||||
+ */
|
||||
+ } else
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
/*
|
||||
* SetNamedPipeHandleState can fail if the handle doesn't have either
|
||||
@@ -1054,7 +1054,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
|
||||
assert(req != NULL);
|
||||
assert(req->type == UV_WRITE);
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
- assert(req->write_buffer.base);
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
req->write_buffer.base,
|
||||
diff --git a/src/win/tty.c b/src/win/tty.c
|
||||
index c359d5601..1b9d4f853 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -367,7 +367,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||||
break;
|
||||
case UV_TTY_MODE_RAW:
|
||||
- flags = ENABLE_WINDOW_INPUT;
|
||||
+ flags = ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT;
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
return UV_ENOTSUP;
|
152
pkg/urbit/compat/poor-mans-nix-shell.sh
Normal file
152
pkg/urbit/compat/poor-mans-nix-shell.sh
Normal file
@ -0,0 +1,152 @@
|
||||
declare -a cdirs
|
||||
declare -a ldirs
|
||||
declare -a pdirs
|
||||
declare -A hdeps
|
||||
sources=(../../nix/sources.json ../../nix/sources-pmnsh.json)
|
||||
patches=compat/$1
|
||||
deriver=urbit-$1-build
|
||||
markfil=.$1~
|
||||
depdirs=
|
||||
nixpath=${NIX_STORE-../build}
|
||||
|
||||
# LDFLAGS doesn't like absolute paths
|
||||
if [ "${nixpath:0:1}" == "/" ]
|
||||
then
|
||||
mkdir -p $nixpath
|
||||
nixpath=$(realpath --relative-to=. $nixpath)
|
||||
fi
|
||||
|
||||
hex2nixbase32 () {
|
||||
local digits='0123456789abcdfghijklmnpqrsvwxyz'
|
||||
local bits=0
|
||||
local left=0 # number of bits left in $bits
|
||||
local i=0
|
||||
while ((1))
|
||||
do
|
||||
while ((left>=5))
|
||||
do
|
||||
echo -n ${digits:$((bits&31)):1}
|
||||
bits=$((bits>>5))
|
||||
left=$((left-5))
|
||||
done
|
||||
if ((i == ${#1}))
|
||||
then
|
||||
break
|
||||
fi
|
||||
char=0x${1:i:2}
|
||||
i=$((i+2))
|
||||
bits=$((bits|(char<<(left))))
|
||||
left=$((left+8))
|
||||
done
|
||||
echo -n ${digits:$bits:1}
|
||||
}
|
||||
|
||||
buildnixdep () {
|
||||
echo Building dependency $key...
|
||||
local cache=https://app.cachix.org/api/v1/cache/${CACHIX_CACHE-}
|
||||
local hash=
|
||||
if [ -n "$url" ]
|
||||
then
|
||||
hash=${hdeps[$key]}
|
||||
dir=$nixpath/$hash-$key
|
||||
if [ -e $dir/$markfil ]
|
||||
then
|
||||
# dependency present, don't reupload
|
||||
hash=
|
||||
else
|
||||
# dependency absent, check the binary cache if configured
|
||||
if [ -n "${CACHIX_CACHE-}" ]
|
||||
then
|
||||
echo Checking binary cache for $hash-$key...
|
||||
narinfo="$cache/${hash}.narinfo"
|
||||
if curl -fLI "$narinfo"
|
||||
then
|
||||
url="$cache/$(curl -fL "$narinfo"|while IFS=: read k v; do if [ "$k" == "URL" ]; then echo $v; fi; done)"
|
||||
echo Found $url
|
||||
strip=0
|
||||
hash=
|
||||
fi
|
||||
fi
|
||||
mkdir -p $dir
|
||||
pushd $dir
|
||||
curl -fL "$url"|(tar --strip $strip -xzf - || true)
|
||||
popd
|
||||
fi
|
||||
else
|
||||
# local dependency
|
||||
dir=../$key
|
||||
fi
|
||||
|
||||
# patch and build the dependency if necessary
|
||||
if [ ! -e $dir/$markfil ]
|
||||
then
|
||||
local patch=$patches/$key.patch
|
||||
[ -e $patch ] && patch -d $dir -p 1 <$patch
|
||||
pushd $dir
|
||||
eval "$cmdprep"
|
||||
eval make "$cmdmake"
|
||||
touch $markfil
|
||||
popd
|
||||
fi
|
||||
|
||||
# if configured, upload freshly built dependency to binary cache
|
||||
if [ -n "$hash" -a -n "${CACHIX_AUTH_TOKEN-}" ]
|
||||
then
|
||||
(
|
||||
echo Uploading freshly built $hash-$key to binary cache...
|
||||
tar -C $dir -czf $hash.tar .
|
||||
local size=$(stat -c '%s' $hash.tar)
|
||||
read filehash _ < <(sha256sum $hash.tar)
|
||||
curl -fL -H "Content-Type: application/gzip" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @"$hash.tar" "$cache/nar"
|
||||
curl -fL -H "Content-Type: application/json" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @- "$cache/${hash}.narinfo" <<EOF
|
||||
{
|
||||
"cStoreHash": "$hash",
|
||||
"cStoreSuffix": "$key",
|
||||
"cNarHash": "sha256:$(hex2nixbase32 $filehash)",
|
||||
"cNarSize": $size,
|
||||
"cFileHash": "$filehash",
|
||||
"cFileSize": $size,
|
||||
"cReferences": [],
|
||||
"cDeriver": "$deriver"
|
||||
}
|
||||
EOF
|
||||
echo Done. ) || true
|
||||
rm $hash.tar || true
|
||||
fi
|
||||
}
|
||||
|
||||
# I have to go over the sources files several times
|
||||
# because jq does not have a way to invoke external programs
|
||||
jqprep='add|to_entries|.[]|.value.pmnsh as $p|select($p and $p.compat.'$1' != false)|(($p + $p.compat.'$1')|del(.compat)) as $o|'
|
||||
|
||||
# list external dependencies, create hash map and directory replacement regex
|
||||
# use -j and \u0000 to work around https://github.com/stedolan/jq/issues/1870
|
||||
while read -rd "" key json
|
||||
do
|
||||
# create 'store hash' from sources.json data and patch
|
||||
patch=$patches/$key.patch
|
||||
read hash _ < <((
|
||||
echo -n $json
|
||||
[ -e $patch ] && cat $patch)|sha256sum)
|
||||
hash=$(hex2nixbase32 $hash)
|
||||
hdeps[$key]=$hash
|
||||
depdirs="$depdirs|gsub(\"\\\\.\\\\./$key\";\"\\(\$d)/$hash-$key\")"
|
||||
done < <(jq --arg deriver "$deriver" -Sscrj "$jqprep"'select(.value.url)|.key," ",{($deriver):(.value|del(.pmnsh) + ({'$1':$o}))},"\u0000"' ${sources[@]})
|
||||
|
||||
# build dependencies, create include and library directory arrays
|
||||
. <(jq --arg nixpath "$nixpath" -sr "$jqprep"'(if .value.url then ".." else $nixpath end) as $d|"
|
||||
unset dir
|
||||
key=\(.key|@sh) \\
|
||||
url=\(.value.url//""|@sh) \\
|
||||
strip=\($o.strip+1) \\
|
||||
cmdprep=\($o.prepare//""'"$depdirs"'|@sh) \\
|
||||
cmdmake=\($o.make//""'"$depdirs"'|@sh) \\
|
||||
buildnixdep # sets dir
|
||||
pdirs+=($dir) # XX support json override a la cdirs/pdirs
|
||||
\($o.include//"."|if type == "array" then . else [.] end|map("cdirs+=(-I$dir/\(.))")|join("\n"))
|
||||
\($o.lib//"."|if type == "array" then . else [.] end|map("ldirs+=(-L$dir/\(.))")|join("\n"))"' ${sources[@]})
|
||||
|
||||
CFLAGS="${CFLAGS-} ${cdirs[@]}"
|
||||
LDFLAGS="${LDFLAGS-} ${ldirs[@]}"
|
||||
|
||||
PKG_CONFIG_PATH="$(IFS=:;echo "${pdirs[*]}"):${PKG_CONFIG_PATH-}"
|
91
pkg/urbit/compat/posix/daemon.c
Normal file
91
pkg/urbit/compat/posix/daemon.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
#include <sys/wait.h>
|
||||
|
||||
/*
|
||||
This is set to the the write-end of a pipe when Urbit is started in
|
||||
daemon mode. It's meant to be used as a signal to the parent process
|
||||
that the child process has finished booting.
|
||||
*/
|
||||
static c3_i _child_process_booted_signal_fd = -1;
|
||||
|
||||
/*
|
||||
This should be called whenever the ship has been booted enough to
|
||||
handle commands from automation code. Specifically, once the Eyre's
|
||||
`chis` interface is up and running.
|
||||
|
||||
In daemon mode, this signals to the parent process that it can
|
||||
exit. Otherwise, it does nothing.
|
||||
|
||||
Once we've sent a signal with `write`, we close the file descriptor
|
||||
and overwrite the global to make it impossible to accidentally do
|
||||
this twice.
|
||||
*/
|
||||
static void _on_boot_completed_cb() {
|
||||
c3_c buf[2] = {0,0};
|
||||
|
||||
if ( -1 == _child_process_booted_signal_fd ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 == write(_child_process_booted_signal_fd, buf, 1) ) {
|
||||
c3_assert(!"_on_boot_completed_cb: Can't write to parent FD");
|
||||
}
|
||||
|
||||
close(_child_process_booted_signal_fd);
|
||||
_child_process_booted_signal_fd = -1;
|
||||
}
|
||||
|
||||
/* u3_daemon_init(): platform-specific daemon mode initialization.
|
||||
|
||||
We use a pipe to communicate between the child and the parent. The
|
||||
parent waits for the child to write something to the pipe and
|
||||
then exits. If the pipe is closed with nothing written to it, get
|
||||
the exit status from the child process and also exit with that status.
|
||||
|
||||
We want the child to write to the pipe once it's booted, so we put
|
||||
`_on_boot_completed_cb` into `u3_Host.bot_f`, which is NULL in
|
||||
non-daemon mode. That gets called once the `chis` service is
|
||||
available.
|
||||
|
||||
In both processes, we are good fork() citizens, and close all unused
|
||||
file descriptors. Closing `pipefd[1]` in the parent process is
|
||||
especially important, since the pipe needs to be closed if the child
|
||||
process dies. When the pipe is closed, the read fails, and that's
|
||||
how we know that something went wrong.
|
||||
|
||||
There are some edge cases around `WEXITSTATUS` that are not handled
|
||||
here, but I don't think it matters.
|
||||
*/
|
||||
void
|
||||
u3_daemon_init()
|
||||
{
|
||||
c3_i pipefd[2];
|
||||
|
||||
if ( 0 != pipe(pipefd) ) {
|
||||
c3_assert(!"Failed to create pipe");
|
||||
}
|
||||
|
||||
pid_t childpid = fork();
|
||||
|
||||
if ( 0 == childpid ) {
|
||||
close(pipefd[0]);
|
||||
_child_process_booted_signal_fd = pipefd[1];
|
||||
u3_Host.bot_f = _on_boot_completed_cb;
|
||||
return;
|
||||
}
|
||||
|
||||
close(pipefd[1]);
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
c3_c buf[2] = {0,0};
|
||||
if ( 1 == read(pipefd[0], buf, 1) ) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
c3_i status;
|
||||
wait(&status);
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
189
pkg/urbit/compat/posix/ptty.c
Normal file
189
pkg/urbit/compat/posix/ptty.c
Normal file
@ -0,0 +1,189 @@
|
||||
/* compat/posix/ptty.c
|
||||
**
|
||||
*/
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
|
||||
/* u3_ptty: POSIX terminal extension to u3_utty.
|
||||
*/
|
||||
typedef struct {
|
||||
u3_utty tty_u; // common tty structure
|
||||
c3_i cug_i; // blocking fcntl flags
|
||||
c3_i nob_i; // nonblocking fcntl flags
|
||||
struct termios bak_u; // cooked terminal state
|
||||
struct termios raw_u; // raw terminal state
|
||||
} u3_ptty;
|
||||
|
||||
/* _term_tcsetattr(): tcsetattr w/retry on EINTR.
|
||||
*/
|
||||
static c3_i
|
||||
_term_tcsetattr(c3_i fil_i, c3_i act_i, const struct termios* tms_u)
|
||||
{
|
||||
c3_i ret_i = 0;
|
||||
c3_w len_w = 0;
|
||||
|
||||
do {
|
||||
// abort pathological retry loop
|
||||
//
|
||||
if ( 100 == ++len_w ) {
|
||||
fprintf(stderr, "term: tcsetattr loop: %s\r\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret_i = tcsetattr(fil_i, act_i, tms_u);
|
||||
} while ( (-1 == ret_i) && (EINTR == errno) );
|
||||
|
||||
return ret_i;
|
||||
}
|
||||
|
||||
/* _ttyf_start_raw_input(): sets the tty to raw input.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_start_raw_input(u3_utty* uty_u)
|
||||
{
|
||||
u3_ptty* pty_u = (u3_ptty*)uty_u;
|
||||
if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->raw_u) ) {
|
||||
return c3n;
|
||||
}
|
||||
if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->nob_i) ) {
|
||||
c3_assert(!"init-fcntl");
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_start_raw_input(): ends raw input on the tty.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_end_raw_input(u3_utty* uty_u)
|
||||
{
|
||||
u3_ptty* pty_u = (u3_ptty*)uty_u;
|
||||
if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->bak_u) ) {
|
||||
return c3n;
|
||||
}
|
||||
if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->cug_i) ) {
|
||||
c3_assert(!"exit-fcntl");
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_hija(): hijacks the tty for cooked output.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_hija(u3_utty* uty_u)
|
||||
{
|
||||
u3_ptty* pty_u = (u3_ptty*)uty_u;
|
||||
if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->bak_u) ) {
|
||||
perror("hija-tcsetattr-1");
|
||||
c3_assert(!"hija-tcsetattr");
|
||||
}
|
||||
if ( -1 == fcntl(1, F_SETFL, pty_u->cug_i) ) {
|
||||
perror("hija-fcntl-1");
|
||||
c3_assert(!"hija-fcntl");
|
||||
}
|
||||
if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->bak_u) ) {
|
||||
perror("hija-tcsetattr-0");
|
||||
c3_assert(!"hija-tcsetattr");
|
||||
}
|
||||
if ( -1 == fcntl(0, F_SETFL, pty_u->cug_i) ) {
|
||||
perror("hija-fcntl-0");
|
||||
c3_assert(!"hija-fcntl");
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_loja(): releases the tty from cooked output.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_loja(u3_utty* uty_u)
|
||||
{
|
||||
u3_ptty* pty_u = (u3_ptty*)uty_u;
|
||||
if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->raw_u) ) {
|
||||
perror("loja-tcsetattr-1");
|
||||
c3_assert(!"loja-tcsetattr");
|
||||
}
|
||||
if ( -1 == fcntl(1, F_SETFL, pty_u->nob_i) ) {
|
||||
perror("hija-fcntl-1");
|
||||
c3_assert(!"loja-fcntl");
|
||||
}
|
||||
if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->raw_u) ) {
|
||||
perror("loja-tcsetattr-0");
|
||||
c3_assert(!"loja-tcsetattr");
|
||||
}
|
||||
if ( -1 == fcntl(0, F_SETFL, pty_u->nob_i) ) {
|
||||
perror("hija-fcntl-0");
|
||||
c3_assert(!"loja-fcntl");
|
||||
}
|
||||
return c3y;
|
||||
}
|
||||
|
||||
/* _ttyf_get_winsize(): gets the tty window size.
|
||||
*/
|
||||
static c3_o
|
||||
_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l)
|
||||
{
|
||||
struct winsize siz_u;
|
||||
if ( 0 == ioctl(uty_u->fid_i, TIOCGWINSZ, &siz_u) )
|
||||
{
|
||||
*col_l = siz_u.ws_col;
|
||||
*row_l = siz_u.ws_row;
|
||||
return c3y;
|
||||
} else {
|
||||
return c3n;
|
||||
}
|
||||
}
|
||||
|
||||
/* u3_ptty_init(): initialize platform-specific tty.
|
||||
*/
|
||||
u3_utty*
|
||||
u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c)
|
||||
{
|
||||
u3_ptty* pty_u = c3_calloc(sizeof(u3_ptty));
|
||||
u3_utty* uty_u = &pty_u->tty_u;
|
||||
|
||||
if ( !isatty(0) || !isatty(1) ) {
|
||||
*err_c = "not a tty";
|
||||
c3_free(pty_u);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uv_pipe_init(lup_u, &uty_u->pin_u.pip_u, 0);
|
||||
uv_pipe_init(lup_u, &uty_u->pop_u.pip_u, 0);
|
||||
uv_pipe_open(&uty_u->pin_u.pip_u, 0);
|
||||
uv_pipe_open(&uty_u->pop_u.pip_u, 1);
|
||||
|
||||
// Load old terminal state to restore.
|
||||
//
|
||||
{
|
||||
if ( 0 != tcgetattr(uty_u->fid_i, &pty_u->bak_u) ) {
|
||||
c3_assert(!"init-tcgetattr");
|
||||
}
|
||||
if ( -1 == fcntl(uty_u->fid_i, F_GETFL, &pty_u->cug_i) ) {
|
||||
c3_assert(!"init-fcntl");
|
||||
}
|
||||
pty_u->cug_i &= ~O_NONBLOCK; // could fix?
|
||||
pty_u->nob_i = pty_u->cug_i | O_NONBLOCK; // O_NDELAY on older unix
|
||||
}
|
||||
|
||||
// Construct raw termios configuration.
|
||||
//
|
||||
{
|
||||
pty_u->raw_u = pty_u->bak_u;
|
||||
|
||||
pty_u->raw_u.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
|
||||
pty_u->raw_u.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
|
||||
pty_u->raw_u.c_cflag &= ~(CSIZE | PARENB);
|
||||
pty_u->raw_u.c_cflag |= CS8;
|
||||
pty_u->raw_u.c_oflag &= ~(OPOST);
|
||||
pty_u->raw_u.c_cc[VMIN] = 0;
|
||||
pty_u->raw_u.c_cc[VTIME] = 0;
|
||||
}
|
||||
|
||||
uty_u->fid_i = 1;
|
||||
uty_u->sta_f = _ttyf_start_raw_input;
|
||||
uty_u->sto_f = _ttyf_end_raw_input;
|
||||
uty_u->hij_f = _ttyf_hija;
|
||||
uty_u->loj_f = _ttyf_loja;
|
||||
uty_u->wsz_f = _ttyf_get_winsize;
|
||||
return uty_u;
|
||||
}
|
11
pkg/urbit/compat/posix/rsignal.h
Normal file
11
pkg/urbit/compat/posix/rsignal.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _RSIGNAL_H
|
||||
#define _RSIGNAL_H
|
||||
|
||||
#define rsignal_jmpbuf sigjmp_buf
|
||||
#define rsignal_setjmp(buf) sigsetjmp((buf), 1)
|
||||
#define rsignal_longjmp siglongjmp
|
||||
#define rsignal_install_handler signal
|
||||
#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN)
|
||||
#define rsignal_setitimer setitimer
|
||||
|
||||
#endif//_RSIGNAL_H
|
141
pkg/urbit/configure
vendored
141
pkg/urbit/configure
vendored
@ -1,16 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
|
||||
URBIT_VERSION="$(cat ./version)"
|
||||
|
||||
deps=" \
|
||||
curl gmp sigsegv argon2 ed25519 ent h2o scrypt uv murmur3 secp256k1 \
|
||||
softfloat3 ssl crypto z lmdb ge-additions aes_siv pthread \
|
||||
# we require pkg-config metadata to statically link these
|
||||
#
|
||||
pkgc_deps=" \
|
||||
libcurl \
|
||||
libh2o \
|
||||
liburcrypt-0 \
|
||||
libuv \
|
||||
openssl \
|
||||
"
|
||||
|
||||
headers=" \
|
||||
ivory.h ca-bundle.h \
|
||||
deps=" \
|
||||
ent \
|
||||
gmp \
|
||||
lmdb \
|
||||
murmur3 \
|
||||
pthread \
|
||||
sigsegv \
|
||||
softfloat3 \
|
||||
"
|
||||
|
||||
headers=" \
|
||||
ca-bundle.h \
|
||||
ivory.h \
|
||||
"
|
||||
|
||||
echo '#pragma once' >include/config.h
|
||||
@ -21,10 +37,41 @@ defmacro () {
|
||||
|
||||
defmacro URBIT_VERSION "\"$URBIT_VERSION\""
|
||||
|
||||
[ -n "$MEMORY_DEBUG" ] && defmacro U3_MEMORY_DEBUG 1
|
||||
[ -n "$MEMORY_LOG" ] && defmacro U3_MEMORY_LOG 1
|
||||
[ -n "$CPU_DEBUG" ] && defmacro U3_CPU_DEBUG 1
|
||||
[ -n "$EVENT_TIME_DEBUG" ] && defmacro U3_EVENT_TIME_DEBUG 1
|
||||
opt_debug=
|
||||
opt_static=
|
||||
|
||||
while test $# != 0
|
||||
do
|
||||
case $1 in
|
||||
--enable-debug)
|
||||
opt_debug=1
|
||||
;;
|
||||
--disable-debug)
|
||||
opt_debug=
|
||||
;;
|
||||
--enable-static)
|
||||
opt_static=1
|
||||
;;
|
||||
--enable-shared)
|
||||
opt_static=
|
||||
;;
|
||||
--disable-static)
|
||||
opt_static=
|
||||
;;
|
||||
--disable-shared)
|
||||
opt_static=1
|
||||
;;
|
||||
*)
|
||||
echo "unrecognized option: $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[ -n "${MEMORY_DEBUG-}" ] && defmacro U3_MEMORY_DEBUG 1
|
||||
[ -n "${MEMORY_LOG-}" ] && defmacro U3_MEMORY_LOG 1
|
||||
[ -n "${CPU_DEBUG-}" ] && defmacro U3_CPU_DEBUG 1
|
||||
[ -n "${EVENT_TIME_DEBUG-}" ] && defmacro U3_EVENT_TIME_DEBUG 1
|
||||
|
||||
if [ -n "${HOST-}" ]
|
||||
then os=$(sed 's$^[^-]*-\([^-]*\)-.*$\1$' <<< "$HOST")
|
||||
@ -58,18 +105,58 @@ esac
|
||||
|
||||
# TODO Determine if the target cpu is little or big endian.
|
||||
case $(tr A-Z a-z <<< $os) in
|
||||
*mingw*)
|
||||
# mingw builds are static-only
|
||||
#
|
||||
opt_static=1
|
||||
|
||||
# ensure required mingw packages are installed
|
||||
mpkgs=(cmake curl gcc jq make)
|
||||
pacman -S --needed autoconf automake-wrapper libtool patch ${mpkgs[@]/#/mingw-w64-x86_64-}
|
||||
|
||||
. compat/poor-mans-nix-shell.sh mingw
|
||||
compat/create-include-files.sh 'stat -c %s' /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt
|
||||
|
||||
defmacro U3_OS_mingw 1
|
||||
|
||||
deps="${deps/sigsegv}"
|
||||
compat="${compat-} mingw"
|
||||
;;
|
||||
m1brew)
|
||||
# ensure required packages are installed
|
||||
brew install -q autoconf automake bash cmake coreutils gmp jq libsigsegv libtool libuv openssl pkgconfig
|
||||
|
||||
if (( ${BASH_VERSION%%.*} < 5 ))
|
||||
then
|
||||
echo Running bash version $BASH_VERSION is too low, please restart bash to use freshly installed one
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# for some reason pkg-config does not pick up openssl
|
||||
export PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig:${PKG_CONFIG_PATH-}"
|
||||
|
||||
. compat/poor-mans-nix-shell.sh m1brew
|
||||
compat/create-include-files.sh 'stat -f %z' /etc/ssl/cert.pem
|
||||
|
||||
defmacro U3_OS_osx 1
|
||||
|
||||
compat="${compat-} posix m1brew"
|
||||
;;
|
||||
*linux*)
|
||||
defmacro U3_OS_linux 1
|
||||
defmacro U3_OS_PROF 1
|
||||
;;
|
||||
*darwin*)
|
||||
defmacro U3_OS_osx 1
|
||||
defmacro U3_OS_PROF 1
|
||||
;;
|
||||
*apple*)
|
||||
defmacro U3_OS_osx 1
|
||||
defmacro U3_OS_PROF 1
|
||||
;;
|
||||
*freebsd*)
|
||||
defmacro U3_OS_bsd 1
|
||||
osdeps="kvm"
|
||||
deps="$deps kvm" # XX use new compat.mk pattern
|
||||
;;
|
||||
*openbsd*)
|
||||
defmacro U3_OS_bsd 1
|
||||
@ -80,19 +167,39 @@ case $(tr A-Z a-z <<< $os) in
|
||||
;;
|
||||
esac
|
||||
|
||||
for dep in ${osdeps-} $deps
|
||||
do LDFLAGS="${LDFLAGS-} -l$dep"
|
||||
${PKG_CONFIG-pkg-config} --cflags --libs $dep 2>/dev/null || true
|
||||
PKG_CONFIG="${PKG_CONFIG-pkg-config}"
|
||||
|
||||
if [ -n "${opt_static-}" ]
|
||||
then
|
||||
CFLAGS="${CFLAGS-} -static"
|
||||
# XX can't set -static here due libuv's -ldl on MacOS
|
||||
#
|
||||
# LDFLAGS="${LDFLAGS-} -static"
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
fi
|
||||
|
||||
CFLAGS="${CFLAGS-} $($PKG_CONFIG --cflags $pkgc_deps)"
|
||||
LDFLAGS="${LDFLAGS-} $($PKG_CONFIG --libs $pkgc_deps)"
|
||||
|
||||
for dep in $deps; do
|
||||
LDFLAGS="${LDFLAGS-} -l$dep"
|
||||
done
|
||||
|
||||
for header in $headers
|
||||
do LDFLAGS="${LDFLAGS-} -I$header"
|
||||
for header in $headers; do
|
||||
CFLAGS="${CFLAGS-} -I$header"
|
||||
done
|
||||
|
||||
compat="${compat-posix}"
|
||||
for citem in $compat; do
|
||||
CFLAGS="${CFLAGS-} -Icompat/$citem"
|
||||
done
|
||||
|
||||
cat >config.mk <<EOF
|
||||
CFLAGS := ${CFLAGS-} -funsigned-char -ffast-math -std=gnu99
|
||||
CFLAGS := $CFLAGS -funsigned-char -ffast-math -fcommon -std=gnu99
|
||||
LDFLAGS := $LDFLAGS
|
||||
CC := ${CC-cc}
|
||||
compat := $compat
|
||||
debug := $opt_debug
|
||||
EOF
|
||||
|
||||
echo == config.mk == >&2
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user