...
 
Commits (14)
This diff is collapsed.
......@@ -14,7 +14,6 @@ members = [
# qaul.net main services
"libqaul/service/chat",
# "libqaul/service/feed",
"libqaul/service/files",
"libqaul/service/voices",
......@@ -38,7 +37,7 @@ members = [
"netmod-wd",
# android build support
"librobot",
"android-support",
# test binaries
"clients/multinode-test",
......
......@@ -11,7 +11,7 @@ edition = "2018"
[dependencies]
id = { version = "0.4", path = "../ratman/identity", features = ["digest", "random", "aligned"], package = "ratman-identity" }
async-std = { version = "1.0", features = ["unstable", "attributes"] }
async-std = { version = "=1.5", features = ["unstable", "attributes"] }
bincode = "1.0"
failure = "0.1"
hex = "0.4"
......
......@@ -19,8 +19,8 @@ use tracing::info;
///
/// [builder]: struct.Builder.html
pub struct Library {
/// The main management path
pub(crate) root: Dirs,
// /// The main management path
// pub(crate) root: Dirs,
/// Table with encrypted user metadata
pub(crate) users: RwLock<UserTable>,
/// Cache of tag/path mappings
......@@ -34,7 +34,7 @@ pub struct Library {
impl Library {
/// Internally called setup function
pub(crate) fn init(self) -> Result<Self> {
self.root.scaffold()?;
// self.root.scaffold()?;
Ok(self)
}
......
......@@ -67,7 +67,7 @@ impl Builder {
let store = RwLock::new(Store::new());
let subs = SubHub::new();
Ok(Arc::new(Library {
root,
// root,
users,
tag_cache,
store,
......@@ -98,17 +98,17 @@ impl Builder {
/// Consume the builder and create a Library
pub fn build(self) -> Result<Arc<Library>> {
let root = Dirs::new(
self.offset
.expect("Builder without `offset` cannot be built"),
);
// let root = Dirs::new(
// self.offset
// .expect("Builder without `offset` cannot be built"),
// );
let users = RwLock::new(UserTable::new());
let tag_cache = RwLock::new(TagCache::new());
let store = RwLock::new(Store::new());
let subs = SubHub::new();
Library {
root,
// root,
users,
tag_cache,
store,
......
[package]
name = "librobot"
name = "libqauldroid"
description = "A libqaul and ratman shim for Android"
version = "0.1.0"
license = "APGL-3.0-or-later"
......@@ -7,13 +7,26 @@ authors = ["Katharina Fey <kookie@spacekookie.de>", "Leonora Tindall <nora@nora.
edition = "2018"
[lib]
name = "robot"
name = "qauldroid"
crate-type = ["cdylib"]
[dependencies]
async-std = "1.5"
jni = { version = "0.14", default-features = false }
tempfile = "3.0"
# tracing-subscriber = { version = "0.2", features = ["fmt"] }
tracing = { version = "0.1", features = ["log", "log-always"] }
libqaul = { path = "../libqaul" }
libqaul-http = { path = "../libqaul/http" }
libqaul-rpc = { path = "../libqaul/rpc" }
qaul-chat = { path = "../libqaul/service/chat" }
netmod-wd = { path = "../netmod-wd" }
ratman = { path = "../ratman" }
ratman-configure = { path = "../ratman/configure" }
netmod-wd = { path = "../netmod-wd" }
\ No newline at end of file
ratman-configure = { path = "../ratman/configure", features = ["android"] }
log = "*"
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.8"
# qaul.net android support
This library provides android specific bindings for the qaul.net
ecosystem (`libqaul`, `ratman`, `ratman-configure`, `netmod-wd`, and
`netmod-tcp`)
You don't need to build this library by yourself, this is handled by
the android build harness. If you want to develop on this crate (for
testing or other reasons), a normal Rust development setup will be
enough.
//! qaul.net android interop library
//!
//! A lot of functions are handled internally, for example after
//! spawning the http server, the main way of communicating with the
//! libqaul stack is via the http api. Some functions need to be
//! exposed from the services, for example for more efficient audio
//! streaming or notifications, and those are handled via this
//! library.
//!
//! It can depend on any library in the qaul.net ecosystem, and can
//! also handle initialisation for the hardware drivers on android.
#![cfg(target_os = "android")]
#![allow(non_snake_case)]
use async_std::task::{block_on, spawn};
use jni::objects::{JObject, JString};
use jni::sys::{jint, jlong, jstring};
use jni::JNIEnv;
use std::{
ffi::{CStr, CString},
net::{Ipv4Addr, SocketAddrV4},
sync::Arc,
};
use tempfile::tempdir;
// use tracing_subscriber::fmt;
// use tracing::Level;
#[macro_use]
extern crate log;
extern crate android_logger;
use android_logger::{Config, FilterBuilder};
use log::Level;
use libqaul::Qaul;
use libqaul_http::HttpServer;
use libqaul_rpc::Responder;
use qaul_chat::Chat;
use ratman_configure::{EpBuilder, NetBuilder};
struct AndroidState {
libqaul: Arc<Qaul>,
}
unsafe fn conv_jstring(env: &JNIEnv, s: JString) -> String {
CString::from(CStr::from_ptr(env.get_string(s).unwrap().as_ptr()))
.to_str()
.unwrap()
.into()
}
// Set a panic handler that will logcan print stacktraces
fn init_panic_handling_once() {
use std::sync::Once;
static INIT_BACKTRACES: Once = Once::new();
INIT_BACKTRACES.call_once(move || {
std::panic::set_hook(Box::new(move |panic_info| {
let (file, line) = if let Some(loc) = panic_info.location() {
(loc.file(), loc.line())
} else {
("<unknown>", 0)
};
let reason = panic_info.to_string();
log::error!(
"### Rust `panic!` hit at file '{}', line {}: `{}`",
file,
line,
reason
);
}));
});
}
#[no_mangle]
pub unsafe extern "C" fn Java_net_qaul_app_MainActivity_hello(
env: JNIEnv,
_: JObject,
j_recipient: JString,
) -> jstring {
let recipient = conv_jstring(&env, j_recipient);
let output = env
.new_string("Hello ".to_owned() + recipient.as_str())
.unwrap();
output.into_inner()
}
/// Function "start_server" that takes a port and path
///
/// The port is used to listen on for the http api, the path is the
/// location of the compiled webui assets. This function bootstraps
/// the qaul.net stack via ratman-configure and libqaul-http.
#[no_mangle]
pub unsafe extern "C" fn Java_net_qaul_app_MainActivity_startServer(
env: JNIEnv,
_: JObject,
port: jint,
path: JString,
) -> jlong {
android_logger::init_once(Config::default().with_min_level(Level::Trace));
init_panic_handling_once();
trace!("Hello from Rust, about to bootstrap the code, yo");
let port = port as u16;
let path = conv_jstring(&env, path);
let net = NetBuilder::new()
.endpoint(EpBuilder::tcp("0.0.0.0".into(), port + 1, false))
//.endpoint(EpBuilder::wifi_direct())
.build();
trace!("Network builder done: {:?}", net);
let router = net.into_router();
trace!("Router done");
let libqaul = Qaul::new(router);
let chat = block_on(async { Chat::new(Arc::clone(&libqaul)).await }).unwrap();
trace!("Chat service done");
let http = HttpServer::set_paths(
path,
Responder {
qaul: Arc::clone(&libqaul),
chat: chat,
},
);
trace!("Http server done");
// Spawn the http server off into the background
spawn(async move { http.listen(&format!("127.0.0.1:{}", port)) });
trace!("Chat service listening done");
let boxed = Box::new(AndroidState { libqaul });
Box::into_raw(boxed) as i64
}
#!/usr/bin/env bash
# Don't call this script directly, use the build.sh script instead
set -e
/qaul.net/clients/android/gradlew cargoBuild
chown $1:$2 -R /qaul.net
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
local.properties
.idea
.DS_Store
/build
/captures
build
captures
.externalNativeBuild
.cxx
app/gradle
app/gradlew*
\ No newline at end of file
......@@ -11,7 +11,7 @@ ENV ANDROID_HOME="/opt/android-sdk" \
ENV ANDROID_SDK_TOOLS_VERSION="4333796"
# Get the latest version from https://developer.android.com/ndk/downloads/index.html
ENV ANDROID_NDK_VERSION="21"
ENV ANDROID_NDK_VERSION="21b"
# nodejs version
ENV NODE_VERSION="10.x"
......@@ -163,19 +163,7 @@ RUN echo "Installing sdk tools ${ANDROID_SDK_TOOLS_VERSION}" && \
"add-ons;addon-google_apis-google-19" \
"add-ons;addon-google_apis-google-18" \
"add-ons;addon-google_apis-google-17" \
"add-ons;addon-google_apis-google-16" > /dev/null && \
echo "Installing emulator " && \
yes | "$ANDROID_HOME"/tools/bin/sdkmanager "emulator" > /dev/null && \
echo "Installing kotlin" && \
wget --quiet -O sdk.install.sh "https://get.sdkman.io" && \
bash -c "bash ./sdk.install.sh > /dev/null && source ~/.sdkman/bin/sdkman-init.sh && sdk install kotlin" && \
rm -f sdk.install.sh && \
# Install Flutter sdk
cd /opt && \
wget --quiet https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.5.4-hotfix.2-stable.tar.xz -O flutter.tar.xz && \
tar xf flutter.tar.xz && \
rm -f flutter.tar.xz && \
flutter config --no-analytics
"add-ons;addon-google_apis-google-16" > /dev/null
# Install Rust toolchains
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
......
......@@ -37,17 +37,11 @@ help you configure them.
Run the following command to just build the Rust code.
```console
$ docker run --rm -it -v /path/to/qaul.net:/qaul.net \
qaulnet/android-build-env /qaul.net/clients/android/gradlew cargoBuild
$ clients/android/build.sh
```
Remember that you are root in the container (meaning uid 0), meaning
that you will have to chown the build files to avoid permission errors
in the next step:
```console
$ sudo chown your_user:your_group -R clients/android
```
This script will take care of permission issues caused by the
container building everything as root already.
- TODO: build the webui
......@@ -57,7 +51,7 @@ command-line to build an app for publishing.
```console
$ cd clients/android
$ ./gradlew assemble
$ clients/android/gradlew assemble
```
A finished APK will appear in in `clients/android/app/build/outputs/apk/debug`.
......
......@@ -36,10 +36,10 @@ dependencies {
}
cargo {
module = "../../../librobot"
module = "../../../android-support"
targetDirectory = "../../../target"
libname = "robot"
targetIncludes = ['librobot.so']
libname = "qauldroid"
targetIncludes = ['libqauldroid.so']
targets = ["arm64"]
targets = ["arm64"]
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.qaul.app">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
......
......@@ -3,14 +3,17 @@ package net.qaul.app;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the native library on application startup.
protected long libqaulState;
static {
System.loadLibrary("robot");
// The "android-support" crate creates a dynamic library called "libqauldroid"
// which we can include here simply via "qauldroid" because it's being put
// into the library search path via ~ m a g i c ~
System.loadLibrary("qauldroid");
}
@Override
......@@ -20,10 +23,14 @@ public class MainActivity extends AppCompatActivity {
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText("qaul.net");
tv.setText(hello("qaul.net"));
Log.d("rust", hello("World"));
// Start the libqaul machinery under the hood
this.libqaulState = this.startServer(5000, "/");
System.out.println(this.libqaulState);
}
public native String hello(String to);
public native long startServer(int port, String path);
}
package net.qaul.app
/** A bridge interface for native initialisation */
class NativeBridge {
private val libqaulState: Long? = null;
protected fun init() {
}
/**
* Debugging method only, probably should be removed.
*
* @param to input string to the Rust code
* @return different string based on the input
*/
external fun hello(to: String?): String?
/**
* Start the main application server.
*
* This will bootstrap the libqaul service stack from the bottom up,
* starting with the router and network modules. Make sure that
* #{wdSetup} and #{wdSendHook} are available to the native run context.
*
* @param port the port to run the webgui http server on
* @param path the path to the webgui sources in internal storage
*
* @return application pointer to the libqaul android state
* for future transactions (currently not used)
*/
protected external fun startServer(port: Int, path: String?): Long;
}
\ No newline at end of file
package net.qaul.app
import android.content.IntentFilter
import android.net.wifi.p2p.WifiP2pManager
/** A handler for wifi direct messages and state */
class WifiDirectHandler {
private val intentFilter = IntentFilter()
init {
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
// Indicates a change in the list of available peers.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
// Indicates the state of Wi-Fi P2P connectivity has changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
// Indicates this device's details have changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
}
}
\ No newline at end of file
#!/usr/bin/env bash
set -ex
BASEDIR=$(realpath $(dirname "$0"))
USER=$(id -u)
GROUP=$(id -g)
docker run --rm -it -v $BASEDIR/../../:/qaul.net qaulnet/android-build-env \
/qaul.net/clients/android/.build_nested.sh $USER $GROUP
......@@ -12,7 +12,7 @@ netmod-tcp = { path = "../../netmod-tcp" }
ratman = { path = "../../ratman" }
ratman-configure = { path = "../../ratman/configure" }
async-std = { version = "1.0", features = ["attributes"] }
async-std = { version = "=1.5", features = ["attributes"] }
clap = { version = "2.0", features = ["wrap_help", "color"] }
directories = "2.0"
tracing = "0.1"
......
......@@ -50,7 +50,7 @@ impl State {
router.add_endpoint(ep).await;
let dirs = ProjectDirs::from("net", "qaul", "hubd").unwrap();
let qaul = Qaul::new(Arc::clone(&router), dirs.data_dir());
let qaul = Qaul::new(Arc::clone(&router));
Self { qaul, router }
}
......
......@@ -8,6 +8,6 @@ license = "GPL-3.0"
[dependencies]
libqaul = { path = "../../libqaul" }
ratman = { path = "../../ratman" }
async-std = { version = "1.0", features = ["attributes"] }
async-std = { version = "=1.5", features = ["attributes"] }
futures = "0.3"
tempfile = "3.0"
\ No newline at end of file
......@@ -7,8 +7,7 @@ async fn main() -> Result<()> {
let r = Router::new();
// TDOD: Add network drivers
let dir = tempfile::tempdir().unwrap();
let q = Qaul::new(r, dir.path());
let q = Qaul::new(r);
let user = q.users().create("password").await?;
let msg = q.messages();
......
......@@ -13,5 +13,5 @@ libqaul-http = { path = "../../libqaul/http" }
qaul-chat = { path = "../../libqaul/service/chat" }
qaul-voices = { path = "../../libqaul/service/voices" }
async-std = { version = "1.0", features = ["attributes"] }
async-std = { version = "=1.5", features = ["attributes"] }
tempfile = "3.0"
\ No newline at end of file
......@@ -2,8 +2,11 @@ use async_std::sync::Arc;
use ratman::Router;
use std::{env, process};
use {
libqaul::Qaul, libqaul_http::HttpServer, libqaul_rpc::Responder, qaul_chat::Chat,
qaul_voices::Voices,
libqaul::Qaul,
libqaul_http::HttpServer,
libqaul_rpc::Responder,
qaul_chat::Chat,
// qaul_voices::Voices,
};
#[async_std::main]
......@@ -18,15 +21,14 @@ async fn main() {
// Init a basic libqaul stack with no interfaces
let rat = Router::new();
let dir = tempfile::tempdir().unwrap();
let qaul = Qaul::new(rat, dir.path());
let qaul = Qaul::new(rat);
let chat = Chat::new(Arc::clone(&qaul)).await.unwrap();
let voices = Voices::new(Arc::clone(&qaul)).await.unwrap();
// let voices = Voices::new(Arc::clone(&qaul)).await.unwrap();
// print the path to the static
println!("Path to static web content: {}", assets);
println!("Open http://127.0.0.1:9900 in your web browser");
// Start the websocket server
HttpServer::block("127.0.0.1:9900", assets, Responder { qaul, chat, voices });
HttpServer::block("127.0.0.1:9900", assets, Responder { qaul, chat });
}
......@@ -12,7 +12,7 @@ libqaul = { path = "../../libqaul" }
qaul-voices = { path = "../../libqaul/service/voices" }
netmod-udp = { path = "../../netmod-udp" }
async-std = "1.0"
async-std = "=1.5"
futures = "0.3"
failure = "0.1"
libpulse-binding = { version = "2.15", features = [] }
......
......@@ -49,8 +49,7 @@ async fn run() {
let router = Router::new();
router.add_endpoint(endpoint).await;
let dir = tempfile::tempdir().unwrap();
let qaul = Qaul::new(router, dir.path());
let qaul = Qaul::new(router);
qaul.services().register("HELLO", |_| {}).await.unwrap();
let user = qaul.users().create("test").await.unwrap();
......
......@@ -13,4 +13,4 @@ ratman = { path = "../../ratman" }
ratman-netmod = { path = "../../ratman/netmod" }
netmod-mem = { path = "../../netmod-mem" }
async-std = "1.0"
async-std = "=1.5"
......@@ -7,4 +7,4 @@ edition = "2018"
[dependencies]
netmod-tcp = { path = "../../netmod-tcp" }
ratman = { path = "../../ratman" }
async-std = { version = "1.0", features = ["attributes"] }
\ No newline at end of file
async-std = { version = "=1.5", features = ["attributes"] }
\ No newline at end of file
......@@ -9,12 +9,12 @@ edition = "2018"
ratman = { path = "../../ratman" }
ratman-harness = { path = "../../ratman/harness" }
libqaul = { path = "../../libqaul" }
libqaul-rpc = { path = "../../libqaul/rpc", features = ["voices", "chat", "json"] }
libqaul-rpc = { path = "../../libqaul/rpc", features = ["chat", "json"] }
libqaul-http = { path = "../../libqaul/http" }
qaul-chat = { path = "../../libqaul/service/chat" }
qaul-voices = { path = "../../libqaul/service/voices" }
async-std = { version = "1.0", features = ["attributes"] }
async-std = { version = "=1.5", features = ["attributes"] }
futures = "0.3"
tempfile = "3.0"
tracing-subscriber = { version = "0.2", features = ["fmt", "env-filter"] }
......
......@@ -4,8 +4,11 @@ use futures::try_join;
use ratman_harness::{temp, Initialize, ThreePoint};
use std::{env, process};
use {
libqaul::Qaul, libqaul_http::HttpServer, libqaul_rpc::Responder, qaul_chat::Chat,
qaul_voices::Voices,
libqaul::Qaul,
libqaul_http::HttpServer,
libqaul_rpc::Responder,
qaul_chat::Chat,
// qaul_voices::Voices,
};
use tracing::Level;
......@@ -29,15 +32,15 @@ async fn main() {
// Initialize a 3 node local qaul network
let mut tp = ThreePoint::new().await;
tp.init_with(|_, arc| Qaul::new(arc, temp().path()));
tp.init_with(|_, arc| Qaul::new(arc));
// services for Node A
let chat_a = Chat::new(Arc::clone(&tp.a())).await.unwrap();
let voices_a = Voices::new(Arc::clone(&tp.a())).await.unwrap();
// let voices_a = Voices::new(Arc::clone(&tp.a())).await.unwrap();
// services for Node B
let chat_b = Chat::new(Arc::clone(&tp.b())).await.unwrap();
let voices_b = Voices::new(Arc::clone(&tp.b())).await.unwrap();
// let voices_b = Voices::new(Arc::clone(&tp.b())).await.unwrap();
// print information for the user
println!("Path to static web content: {}", assets);
......@@ -51,7 +54,7 @@ async fn main() {
Responder {
qaul: Arc::clone(tp.a()),
chat: chat_a,
voices: voices_a,
// voices: voices_a,
},
);
let server_b = HttpServer::set_paths(
......@@ -59,7 +62,7 @@ async fn main() {
Responder {
qaul: Arc::clone(tp.b()),
chat: chat_b,
voices: voices_b,
// voices: voices_b,
},
);
......
......@@ -7,4 +7,4 @@ edition = "2018"
license = "GPL-3.0-or-later"
[dependencies]
async-std = { version = "1.0", features = ["unstable"] }
\ No newline at end of file
async-std = { version = "=1.5", features = ["unstable"] }
\ No newline at end of file
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "qaul";
buildInputs = with pkgs; [
rustup clangStdenv
];
}
......@@ -8,7 +8,7 @@ edition = "2018"
[dependencies]
alexandria = { version = "0.2", path = "../alexandria" }
async-std = { version = "1.0", features = ["attributes", "unstable"] }
async-std = { version = "=1.5", features = ["attributes", "unstable"] }
base64 = "0.10"
bincode = "1.0"
blake2 = "0.8"
......
......@@ -7,8 +7,8 @@ edition = "2018"
license = "AGPL-3.0"
[dependencies]
libqaul = { version = "*", path = ".." }
libqaul-rpc = { version = "*", path = "../rpc" }
libqaul = { path = ".." }
libqaul-rpc = { path = "../rpc" }
serde_json = "1.0"
async-std = "1.0"
......
......@@ -8,7 +8,8 @@
use libqaul_rpc::Responder;
use async_std::{sync::Arc, task};
use async_std::{sync::Arc, task, task::JoinHandle};
use std::io::Result;
use tide::{self, server::Server};
use tide_naive_static_files::StaticFilesEndpoint as StaticEp;
......@@ -17,19 +18,27 @@ mod rest;
mod rpc;
/// State structure for the libqaul http server
pub struct HttpServer;
pub struct HttpServer {
inner: Server<()>,
}
impl HttpServer {
/// open a blocking http connection
pub fn block(addr: &str, path: String, rpc: Responder) {
let app = HttpServer::set_paths(path, rpc);
let Self { inner } = HttpServer::set_paths(path, rpc);
// run server in blocking task
task::block_on(async move { app.listen(addr).await }).unwrap();
task::block_on(async move { inner.listen(addr).await }).unwrap();
}
pub fn listen(self, addr: &str) -> JoinHandle<Result<()>> {
let Self { inner } = self;
let addr = String::from(addr);
task::spawn(async move { inner.listen(&addr).await })
}
/// set http endpoints and paths that returns the http server
pub fn set_paths(path: String, rpc: Responder) -> Server<()> {
pub fn set_paths(path: String, rpc: Responder) -> Self {
let mut app = tide::new();
let rpc_state = Arc::new(rpc);
let rest_state = rpc_state.clone();
......@@ -106,6 +115,6 @@ impl HttpServer {
root: info_path_2.into(),
});
app
Self { inner: app }
}
}
......@@ -6,14 +6,16 @@ authors = ["Katharina Fey <kookie@spacekookie.de>", "jess 3jane <me@jess.coffee>
edition = "2018"
[features]
default = ["proto", "json", "chat", "voices"]
default = ["proto", "json", "chat", "files", "voices"]
proto = ["capnp"]
json = ["serde_json"]
chat = ["qaul-chat"]
files = ["qaul-files"]
voices = ["qaul-voices"]
[dependencies]
qaul-chat = { path = "../service/chat", optional = true }
qaul-files = { path = "../service/files", optional = true }
qaul-voices = { path = "../service/voices", optional = true }
libqaul = { version = "*", path = ".." }
......@@ -21,7 +23,7 @@ capnp = { version = "0.12", optional = true }
serde_json = { version = "1.0", optional = true }
serde = { version = "1.0", features = [ "derive" ] }
async-trait = "0.1"
async-std = { version = "1.0", features = ["attributes"]}
async-std = { version = "=1.5", features = ["attributes"]}
futures = "0.3"
failure = "0.1"
crossbeam-queue = "0.2"
......
......@@ -10,8 +10,8 @@ use libqaul::{
#[cfg(feature = "chat")]
use qaul_chat::{Chat, ChatMessage, Room, RoomId};
#[cfg(feature = "voices")]
use qaul_voices::api::{CallId, CallStatus, IncomingCall, StreamMetadata};
// #[cfg(feature = "voices")]
// use qaul_voices::api::{CallId, CallStatus, IncomingCall, StreamMetadata};
use serde::{Deserialize, Serialize};
use std::{error::Error, fmt::Display};
......@@ -98,45 +98,45 @@ pub enum Request {
/// Update a user
UserUpdate(users::Update),
#[cfg(feature = "voices")]
/// Initiate a call to a remote user
VoicesMakeCall(voices::MakeCall),
// #[cfg(feature = "voices")]
// /// Initiate a call to a remote user
// VoicesMakeCall(voices::MakeCall),
#[cfg(feature = "voices")]
/// Accept a call from a remote user
VoicesAcceptCall(voices::AcceptCall),
// #[cfg(feature = "voices")]
// /// Accept a call from a remote user
// VoicesAcceptCall(voices::AcceptCall),
#[cfg(feature = "voices")]
/// Reject a call
VoicesRejectCall(voices::RejectCall),
// #[cfg(feature = "voices")]
// /// Reject a call
// VoicesRejectCall(voices::RejectCall),
#[cfg(feature = "voices")]
/// Terminate a call
VoicesHangUp(voices::HangUp),
// #[cfg(feature = "voices")]
// /// Terminate a call
// VoicesHangUp(voices::HangUp),
#[cfg(feature = "voices")]
/// Wait for the next incoming call
VoicesNextIncoming(voices::NextIncoming),
// #[cfg(feature = "voices")]
// /// Wait for the next incoming call
// VoicesNextIncoming(voices::NextIncoming),
#[cfg(feature = "voices")]
/// Get the stream metadata for the remote end of a call
VoicesGetMetadata(voices::GetMetadata),
// #[cfg(feature = "voices")]
// /// Get the stream metadata for the remote end of a call
// VoicesGetMetadata(voices::GetMetadata),
#[cfg(feature = "voices")]
/// Push voice samples on to the outgoing call buffer
VoicesPushVoice(voices::PushVoice),
// #[cfg(feature = "voices")]
// /// Push voice samples on to the outgoing call buffer
// VoicesPushVoice(voices::PushVoice),
#[cfg(feature = "voices")]
/// Get the status of a call
VoicesGetStatus(voices::GetStatus),
// #[cfg(feature = "voices")]
// /// Get the status of a call
// VoicesGetStatus(voices::GetStatus),
#[cfg(feature = "voices")]
/// Subscribe to the incoming voice samples of a call
VoicesNextVoice(voices::NextVoice),
// #[cfg(feature = "voices")]
// /// Subscribe to the incoming voice samples of a call
// VoicesNextVoice(voices::NextVoice),
#[cfg(feature = "voices")]
/// Await the termination of a call
VoicesOnHangup(voices::OnHangup),
// #[cfg(feature = "voices")]
// /// Await the termination of a call
// VoicesOnHangup(voices::OnHangup),
}
/// Wrap around all possible response values for piped Rpc protocols
......@@ -182,25 +182,25 @@ pub enum Response {
/// Return available user IDs
UserId(Vec<Identity>),
/// A call id
#[cfg(feature = "voices")]
CallId(CallId),
// /// A call id
// #[cfg(feature = "voices")]
// CallId(CallId),
/// An incoming call
#[cfg(feature = "voices")]
IncomingCall(IncomingCall),
// /// An incoming call
// #[cfg(feature = "voices")]
// IncomingCall(IncomingCall),
/// Metadata about a voice stream
#[cfg(feature = "voices")]
StreamMetadata(StreamMetadata),
// /// Metadata about a voice stream
// #[cfg(feature = "voices")]
// StreamMetadata(StreamMetadata),
/// The status of a call
#[cfg(feature = "voices")]
CallStatus(CallStatus),
// /// The status of a call
// #[cfg(feature = "voices")]
// CallStatus(CallStatus),
/// A set of voice samples
#[cfg(feature = "voices")]
VoiceData(Vec<i16>),
// /// A set of voice samples
// #[cfg(feature = "voices")]
// VoiceData(Vec<i16>),
}
impl From<UserAuth> for Response {
......@@ -281,23 +281,23 @@ impl From<Vec<UserProfile>> for Response {
}
}
#[cfg(feature = "voices")]
impl From<IncomingCall> for Response {
fn from(incoming: IncomingCall) -> Self {
Response::IncomingCall(incoming)
}
}
#[cfg(feature = "voices")]
impl From<StreamMetadata> for Response {
fn from(metadata: StreamMetadata) -> Self {
Response::StreamMetadata(metadata)
}
}
#[cfg(feature = "voices")]
impl From<CallStatus> for Response {
fn from(status: CallStatus) -> Self {
Response::CallStatus(status)
}
}
// #[cfg(feature = "voices")]
// impl From<IncomingCall> for Response {
// fn from(incoming: IncomingCall) -> Self {
// Response::IncomingCall(incoming)
// }
// }
// #[cfg(feature = "voices")]
// impl From<StreamMetadata> for Response {
// fn from(metadata: StreamMetadata) -> Self {
// Response::StreamMetadata(metadata)
// }
// }
// #[cfg(feature = "voices")]
// impl From<CallStatus> for Response {
// fn from(status: CallStatus) -> Self {
// Response::CallStatus(status)
// }
// }
......@@ -2,7 +2,8 @@
use crate::QaulRpc;
use async_trait::async_trait;
use libqaul::{files::FileFilter, users::UserAuth, Identity};
use libqaul::{users::UserAuth, Identity};
use qaul_files::files::FileFilter;
/// Send a file store query
#[derive(PartialEq)]
......
......@@ -8,8 +8,8 @@ pub mod users;
#[cfg(feature = "chat")]
pub mod chat;
#[cfg(feature = "voices")]
pub mod voices;
// #[cfg(feature = "voices")]
// pub mod voices;
mod envelope;
pub use envelope::{Envelope, Request, Response};
......
......@@ -9,10 +9,10 @@ use crate::{ChatExt, ChatRpc};
#[cfg(feature = "chat")]
use qaul_chat::Chat;
#[cfg(feature = "voices")]
use crate::{VoicesExt, VoicesRpc};
#[cfg(feature = "voices")]
use qaul_voices::Voices;
// #[cfg(feature = "voices")]
// use crate::{VoicesExt, VoicesRpc};
// #[cfg(feature = "voices")]
// use qaul_voices::Voices;
/// A type mapper to map RPC requests to libqaul and services
pub struct Responder {
......@@ -21,8 +21,8 @@ pub struct Responder {
#[cfg(feature = "chat")]
pub chat: Arc<Chat>,
#[cfg(feature = "voices")]
pub voices: Arc<Voices>,
// #[cfg(feature = "voices")]
// pub voices: Arc<Voices>,
}
impl Responder {
......@@ -43,14 +43,14 @@ impl Responder {
(&self.chat).apply(request).await
}
#[cfg(feature = "chat")]
async fn respond_voices<R, T>(&self, request: R) -> T
where
R: VoicesRpc<Response = T> + Send + Sync,
T: Send + Sync,
{
self.voices.apply(request).await
}
// #[cfg(feature = "voices")]
// async fn respond_voices<R, T>(&self, request: R) -> T
// where
// R: VoicesRpc<Response = T> + Send + Sync,
// T: Send + Sync,
// {
// self.voices.apply(request).await
// }
/// Primary responder matcher
///
......@@ -65,17 +65,17 @@ impl Responder {
// TODO: currently the ids all map into Response::UserId which is wrong
match req {
// =^-^= Chat Messages =^-^=
#[cfg(feature = "chat")]
//#[cfg(feature = "chat")]
Request::ChatMsgCreate(r) => self.respond_chat(r).await.into(),
// =^-^= Chat Rooms =^-^=
// #[cfg(feature = "chat")]
// Request::ChatRoomList(r) => self.respond_chat(r).await.into(),
#[cfg(feature = "chat")]
//#[cfg(feature = "chat")]
Request::ChatRoomGet(r) => self.respond_chat(r).await.into(),
#[cfg(feature = "chat")]
//#[cfg(feature = "chat")]
Request::ChatLoadRoom(r) => self.respond_chat(r).await.into(),
#[cfg(feature = "chat")]
//#[cfg(feature = "chat")]
Request::ChatRoomCreate(r) => self
.respond_chat(r)
.await
......@@ -123,35 +123,35 @@ impl Responder {
Request::UserGet(r) => self.respond_qaul(r).await.into(),
Request::UserUpdate(r) => self.respond_qaul(r).await.into(),
// =^-^= Voices =^-^=
#[cfg(feature = "voices")]
Request::VoicesMakeCall(r) => self
.respond_voices(r)
.await
.map(|id| Response::CallId(id))
.unwrap_or_else(|e| Response::Error(e.to_string())),
#[cfg(feature = "voices")]
Request::VoicesAcceptCall(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesRejectCall(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesHangUp(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesNextIncoming(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesGetMetadata(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesPushVoice(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesGetStatus(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesOnHangup(r) => self.respond_voices(r).await.into(),
#[cfg(feature = "voices")]
Request::VoicesNextVoice(r) => self
.respond_voices(r)
.await
.map(|samples| Response::VoiceData(samples))
.unwrap_or_else(|e| Response::Error(e.to_string())),
// // =^-^= Voices =^-^=
// #[cfg(feature = "voices")]
// Request::VoicesMakeCall(r) => self
// .respond_voices(r)
// .await
// .map(|id| Response::CallId(id))
// .unwrap_or_else(|e| Response::Error(e.to_string())),
// #[cfg(feature = "voices")]
// Request::VoicesAcceptCall(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesRejectCall(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesHangUp(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesNextIncoming(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesGetMetadata(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesPushVoice(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesGetStatus(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesOnHangup(r) => self.respond_voices(r).await.into(),
// #[cfg(feature = "voices")]
// Request::VoicesNextVoice(r) => self
// .respond_voices(r)
// .await
// .map(|samples| Response::VoiceData(samples))
// .unwrap_or_else(|e| Response::Error(e.to_string())),
tt => panic!(
"Encountered unimplemented parse type: {:#?}\n...so sorry",
......
......@@ -91,19 +91,16 @@ async fn user_delete() {
use async_std::task::block_on;
use libqaul::Qaul;
use qaul_chat::Chat;
use qaul_voices::Voices;
use std::sync::Arc;
let qaul = Arc::new(Qaul::dummy());
let chat = Chat::new(qaul.clone()).await.unwrap();
let voices = Voices::new(qaul.clone()).await.unwrap();
let auth = block_on(qaul.users().create("blep")).unwrap();
assert_eq!(qaul.users().list().await.len(), 1);
let responder = Responder {
qaul: qaul.clone(),
chat: chat,
voices: voices,
};
let req_env = RequestEnv {
......
......@@ -26,7 +26,7 @@ pub use api::{
#[cfg(feature = "chat")]
pub use api::{chat, chat::ChatExt, chat::ChatRpc};
#[cfg(feature = "voices")]
pub use api::{voices, voices::VoicesExt, voices::VoicesRpc};
// #[cfg(feature = "voices")]
// pub use api::{voices, voices::VoicesExt, voices::VoicesRpc};
pub mod json;
//! # RPC Test Environment with 3 Node Simulation
//!
//! The test environment provides a ThreeNode local
//!
//! The test environment provides a ThreeNode local
//! network which is based on the ratman-harness crate.
//! With it, an entire local 3 node network is simulated
//! and can be used to run the RPC tests.
......@@ -8,16 +8,13 @@
#[cfg(test)]
pub(crate) mod rpc_harness {
use async_std::sync::Arc;
use libqaul::{Identity, Qaul};
use libqaul_rpc::{
json::{RequestEnv, ResponseEnv},
Envelope, Responder,
};
use qaul_chat::Chat;
use ratman_harness::{temp, Initialize, ThreePoint};
use {
qaul_chat::Chat,
qaul_voices::Voices,
};
use libqaul::{Qaul, Identity};
/// RPC test state
pub(crate) struct RPC {
......@@ -31,24 +28,28 @@ pub(crate) mod rpc_harness {
pub(crate) async fn init() -> RPC {
// Initialize a basic libqaul stack with no interfaces
let mut tp = ThreePoint::new().await;
tp.init_with(|_, arc| Qaul::new(arc, temp().path()));
tp.init_with(|_, arc| Qaul::new(arc));
// services for Node A
let tp_a = tp.a.clone();
let qaul_a = tp_a.1.unwrap().clone();
let chat_a = Chat::new(Arc::clone(&qaul_a)).await.unwrap();
let voices_a = Voices::new(Arc::clone(&qaul_a)).await.unwrap();
// services for Node B
let tp_b = tp.b.clone();
let qaul_b = tp_b.1.unwrap().clone();
let chat_b = Chat::new(Arc::clone(&qaul_b)).await.unwrap();
let voices_b = Voices::new(Arc::clone(&qaul_b)).await.unwrap();
RPC {
responder_a: Responder {qaul: qaul_a, chat: chat_a, voices: voices_a},
responder_b: Responder {qaul: qaul_b, chat: chat_b, voices: voices_b},
network: tp
responder_a: Responder {
qaul: qaul_a,
chat: chat_a,
},
responder_b: Responder {
qaul: qaul_b,
chat: chat_b,
},
network: tp,
}
}
......@@ -64,14 +65,13 @@ pub(crate) mod rpc_harness {
/// send a RPC call
pub(crate) async fn send(self, json_string: &str, node: u8) -> ResponseEnv {
let req_env: RequestEnv =
serde_json::from_str(json_string).unwrap();
let req_env: RequestEnv = serde_json::from_str(json_string).unwrap();
let Envelope { id, data: req } = req_env.clone().generate_envelope().unwrap();
// Call into libqaul via the rpc utilities
let resp = match node {
1 => self.responder_a.respond(req).await,
_ => self.responder_b.respond(req).await
_ => self.responder_b.respond(req).await,
};
let env = Envelope { id, data: resp };
......
//! # RPC Test Environment Without any Netmods
//!
//!
//! The test environment provides common functions
//! for the RPC tests.
#[cfg(test)]
pub(crate) mod tests {
use async_std::sync::Arc;
use libqaul::{Identity, Qaul};
use libqaul_rpc::{
json::{RequestEnv, ResponseEnv},
Envelope, Responder,
};
use qaul_chat::Chat;
use ratman::Router;
use {
qaul_chat::Chat,
qaul_voices::Voices,
};
use libqaul::{Qaul, Identity};
/// RPC test state
pub(crate) struct RPC {
......@@ -27,20 +24,17 @@ pub(crate) mod tests {
pub(crate) async fn init() -> RPC {
// Initialize a basic libqaul stack with no interfaces
let rat = Router::new();
let dir = tempfile::tempdir().unwrap();
let qaul = Qaul::new(rat, dir.path());
let qaul = Qaul::new(rat);
let chat = Chat::new(Arc::clone(&qaul)).await.unwrap();
let voices = Voices::new(Arc::clone(&qaul)).await.unwrap();
RPC {
responder: Responder {qaul, chat, voices}
responder: Responder { qaul, chat },
}
}
/// send a RPC call
pub(crate) async fn send(self, json_string: &str) -> ResponseEnv {
let req_env: RequestEnv =
serde_json::from_str(json_string).unwrap();
let req_env: RequestEnv = serde_json::from_str(json_string).unwrap();
let Envelope { id, data: req } = req_env.clone().generate_envelope().unwrap();
// Call into libqaul via the rpc utilities
......@@ -52,4 +46,4 @@ pub(crate) mod tests {
resp_env
}
}
}
\ No newline at end of file
}
......@@ -9,7 +9,7 @@ license = "AGPL-3.0"
files = { path = "../files", package = "qaul-files" }
libqaul = { path = "../../", features = ["testing"] }
async-std = "1.0"
async-std = "=1.5"
bincode = "1.0"
chrono = { version = "0.4", features = ["serde"] }
futures = "0.3"
......
......@@ -21,7 +21,7 @@ struct ChatPair {
async fn init() -> ThreePoint<ChatPair> {
let mut tp = ThreePoint::new().await;
tp.init_with(|_, arc| {
let qaul = Qaul::new(arc, temp().path());
let qaul = Qaul::new(arc);
let chat = async_std::task::block_on(async { Chat::new(Arc::clone(&qaul)).await }).unwrap();
ChatPair { qaul, chat }
});
......
......@@ -21,7 +21,7 @@ struct ChatPair {
async fn init() -> ThreePoint<ChatPair> {
let mut tp = ThreePoint::new().await;
tp.init_with(|_, arc| {
let qaul = Qaul::new(arc, temp().path());
let qaul = Qaul::new(arc);
let chat = async_std::task::block_on(async { Chat::new(Arc::clone(&qaul)).await }).unwrap();
ChatPair { qaul, chat }
});
......
......@@ -9,3 +9,4 @@ license = "AGPL-3.0"
identity = { path = "../../../ratman/identity", package = "ratman-identity" }
libqaul = { path = "../../" }
mime = "0.3"
serde = { version = "1.0" }
#![allow(unused)]
use crate::error::Result;
use crate::users::UserAuth;
use crate::Identity;
use serde::{Deserialize, Serialize};
use libqaul::error::Result;
use libqaul::Identity;
use libqaul::users::UserAuth;
pub type FileId = Identity;
/// Local file abstraction
......@@ -74,37 +73,37 @@ pub struct Files<'chain> {
impl<'qaul> Files<'qaul> {
/// Query the local file store for a specific constraint
pub fn query<I>(&self, user: UserAuth, filter: FileFilter) -> Result<I>
where
I: Iterator<Item = FileMeta>,
where
I: Iterator<Item=FileMeta>,
{
self.q.auth.trusted(user)?;
// self.q.auth.trusted(user)?;
unimplemented!()
}
/// List all available files
pub fn list<I>(&self, user: UserAuth) -> Result<I>
where
I: Iterator<Item = FileMeta>,
where
I: Iterator<Item=FileMeta>,
{
self.q.auth.trusted(user)?;
// self.q.auth.trusted(user)?;
unimplemented!()
}
/// Stream one particular file from storage
pub async fn get(&self, user: UserAuth, file: FileId) -> Result<File> {
self.q.auth.trusted(user)?;
// self.q.auth.trusted(user)?;
unimplemented!()
}
/// Adds a new file to the local user's storage
pub fn add(&self, user: UserAuth, name: &str, file: File) -> Result<FileId> {
self.q.auth.trusted(user)?;
// self.q.auth.trusted(user)?;
unimplemented!()
}
/// Delete a file from the local user store
pub fn delete(&self, user: UserAuth, name: FileId) -> Result<()> {
self.q.auth.trusted(user)?;
// self.q.auth.trusted(user)?;
unimplemented!()
}
}