diff --git a/README.md b/README.md index 38dd95093b98c83220d1af039768d0da110cb0ef..a96835a5c0a7a4c83a3939c16d6f94f0569cb788 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,9 @@ be run using the following command. $ GOOS=js GOARCH=wasm go test ./... ``` -Note, this will fail because `wasm/wasm_js.s` contains commands only recognized +Note, this will fail because `utils/utils_js.s` contains commands only recognized by the Go WebAssembly compiler and for some reason not recognized by the test -runner. To get tests to run, temporarily delete the body of `wasm/wasm_js.s` +runner. To get tests to run, temporarily delete the body of `utils/utils_js.s` during testing. ## Testing @@ -65,7 +65,7 @@ global.Go = class { go: { // ... // func Throw(exception string, message string) - 'gitlab.com/elixxir/xxdk-wasm/wasm.throw': (sp) => { + 'gitlab.com/elixxir/xxdk-wasm/utils.throw': (sp) => { const exception = loadString(sp + 8) const message = loadString(sp + 24) throw globalThis[exception](message) diff --git a/examples/ndf.json b/examples/ndf.json new file mode 100644 index 0000000000000000000000000000000000000000..0ca92937841d565ce0ed0243f5f032e86cfbbe55 --- /dev/null +++ b/examples/ndf.json @@ -0,0 +1 @@ +{"Timestamp":"2022-09-02T10:27:19.6661079-07:00","Gateways":[{"Id":"uKOO90b6GDwXcLr/hGU3sjX6O0AmDA4nvC4bDEO7wFMB","Address":"0.0.0.0:8440","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Bin":"SouthAndCentralAmerica"},{"Id":"KDzk21/pQ01RtoOHdh7207dkUqx5Mq7MIJsRPsOKXcMB","Address":"0.0.0.0:8442","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Bin":"CentralEurope"},{"Id":"jgZt6uZkK6tTGRnk0tAmVO9Akv11y0yBPolNkw/e+bAB","Address":"0.0.0.0:8443","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Bin":"EasternEurope"},{"Id":"AFARX39tIj246msuyhutEWlFQv7LSaAe8cR0i+aB59gB","Address":"0.0.0.0:8444","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Bin":"MiddleEast"},{"Id":"EyVHEz37phB8XZVl2N6Lu3p/bxnVIBvoAPhbPXIcpZsB","Address":"0.0.0.0:8441","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Bin":"WesternEurope"}],"Nodes":[{"Id":"uKOO90b6GDwXcLr/hGU3sjX6O0AmDA4nvC4bDEO7wFMC","Address":"","Tls_certificate":"","Status":0},{"Id":"KDzk21/pQ01RtoOHdh7207dkUqx5Mq7MIJsRPsOKXcMC","Address":"","Tls_certificate":"","Status":0},{"Id":"jgZt6uZkK6tTGRnk0tAmVO9Akv11y0yBPolNkw/e+bAC","Address":"","Tls_certificate":"","Status":0},{"Id":"AFARX39tIj246msuyhutEWlFQv7LSaAe8cR0i+aB59gC","Address":"","Tls_certificate":"","Status":0},{"Id":"EyVHEz37phB8XZVl2N6Lu3p/bxnVIBvoAPhbPXIcpZsC","Address":"","Tls_certificate":"","Status":0}],"Registration":{"Address":":18000","ClientRegistrationAddress":"0.0.0.0:11421","Tls_certificate":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","EllipticPubKey":"AWjTOI++PCwzIVLMiXcBHzKtxWShdbBLluGOtbnqd10="},"Notification":{"Address":"","Tls_certificate":""},"Udb":{"Id":"uu49Kr9myQUG0gG8VKwalxmem65pfPu4D2Lk1u8pi/UD","Cert":"-----BEGIN CERTIFICATE-----\r\nMIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV\r\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\r\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp\r\ncDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT\r\nMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV\r\nBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw\r\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh\r\nDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs\r\nWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE\r\ntJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA\r\nm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9\r\nbJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA\r\nAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA\r\nneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf\r\nU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2\r\nqvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4\r\ncyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R\r\ntgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5\r\n6m52PyzMNV+2N21IPppKwA==\r\n-----END CERTIFICATE-----\r\n","Address":"127.0.0.1:18001","DhPubKey":"eyJWYWx1ZSI6MTQ3MTM5NzkxNDA3Njk5MjM0OTk3MTkyOTEwNTk1MDc1NTI3NDM1NDYwMDYxNTI0NzcyOTQ0MzQzNzQ4NjgxMjA2MjY1ODY5ODQ2NjQyMzMyMzQ1NzA3OTkwNjc3NDA2MDQwMTQ1MTc3NTM0MzIxNTM4MTgyNDQwNzE3ODkwMzU5OTkzNDI4Njg2MTA5NTI1MjAyMTE4MjA1MjIzODkxNDMxODk5MTY4MjYxOTU5MTIzOTc3MDcxMzYzMDIzMTYxOTgzNTIwNjIwNDA1MjM1NzQ3NTkwMDg0NjkzNjYxODA0MTE1NjkxNjc3NDg4MDQ5MzY3NTIxMTk1Nzk1NjAyOTcxNjI1MzYzODY0NDkyOTk5NDk2NTI3MTkwNjA2MzgzNTkzMjg5NjA3MDk3MTg1MjEwNzkyOTk5OTgyNjY3Mjc5MDk1Njc4ODI2NTE1OTA5NTA2MDQyNTA4MDgxNDU2NDkzNDU2OTk3MzU0MDQwNTA0NDM2NTMwMTI2OTQwNDM0MzkxNjEyMTMyNTcyMjEwNDY5OTExMDY4NjAyMzQ2MTExNjAyOTUwNzQyNzk2NzUyNDQ2MDQ0MTk3OTM4OTQ2ODg1ODQ1MTE5NzMzNjU0NzQzOTc1OTY4NTIwNzYyNDgyODI3MzY1NDM0MDMxNDc5NjEzOTE3MTQ5ODgzNjQwMzQ3ODU1NTEyODY0ODc5NTU2NjY5ODcxNjI1NzAyMzczNTU1MTkxMTE5NjM2NDE0MDg4NDc2NjUyODc4NTYzNzAwNzE2NTAxNzk5NDA5NjA3NDI3Njg5OTI5MTcxMjY2MTQ3MDQ3NzU2MjA0Njg5NDM5NTE5MDkyNjgwNDk0ODg2MTMxNDc0NjY1MzMxNzE4MDY0MjQ3NzQ0MTE5MTQ2Mjg4MDY0NjIwOTMzMjQ4OTg3MjAzNzc4MjQxNTEzNTQ2MTc1NDQ1NjM4ODU4MjU0MTk0NTQ4MjY3NjIwOTYwNTEwMjc0Nzc2NjU4Mzc3MDM4OTcxNzkzMDUxOTAxNTk1NDkyNDQ1OTQzNjk3NTE5NTExMjAzOTkzMzgxOTAxNjI3NzY2Mjk1MDc1NDQ0NTM3NDIyMTc5ODgxMDI3NjcwMTE4MzM2NzgzODA5MjcxODAxNTMwNjk4MzE5ODIxNjg2Mzc1ODc5NTY1NzgwMDcxMjE0MzMwOTA5ODk5MTU1MTExNjQ3Mjc5NTg5NDc0ODIyMzkzMDQ3OTU1NzMyMTY3NzI4ODI1NTMyNDQ1ODg4MDk2MTY1NzIxMzExNDcxNTIyODUxLCJGaW5nZXJwcmludCI6MTY4MDE1NDE1MTEyMzMwOTgzNjN9"},"E2e":{"Prime":"E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873847AEF49F66E43873","Small_prime":"","Generator":"2"},"Cmix":{"Prime":"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF","Small_prime":"","Generator":"2"},"AddressSpace":[{"Size":32,"Timestamp":"2022-09-02T10:27:19.6392244-07:00"}],"ClientVersion":"","WhitelistedIds":null,"WhitelistedIpAddresses":null,"RateLimits":{"Capacity":0,"LeakedTokens":0,"LeakDuration":0}} \ No newline at end of file diff --git a/examples/sendE2E/index.html b/examples/sendE2E/index.html new file mode 100644 index 0000000000000000000000000000000000000000..27067671ba8e358138343310445fb490bd21dcab --- /dev/null +++ b/examples/sendE2E/index.html @@ -0,0 +1,70 @@ +<!-- + ~ Copyright © 2020 xx network SEZC /// + ~ /// + ~ Use of this source code is governed by a license that can be found in the /// + ~ LICENSE file /// + --> + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Receiver</title> + + <link rel="stylesheet" type="text/css" href="../styles.css"> + <link rel="shortcut icon" type="image/x-icon" href="receiver-favicon.ico" /> + + <script type="text/javascript" src="xxdk.js"></script> + <script type="text/javascript" src="../wasm_exec.js"></script> + <script> + // Use the encoder to convert a string to Uint8Array using enc.encode() + + const go = new Go(); + WebAssembly.instantiateStreaming(fetch("../xxdk.wasm"), go.importObject).then((result) => { + go.run(result.instance); + + LogLevel(0); + + const recipientContactFile = ''; + const myContactFileName = 'myE2eContact.xxc'; + const statePath = 'statePathRecipient'; + const statePass = 'password'; + + document.getElementById('ndf-input') + .addEventListener('change', function (e) { + let reader = new FileReader(); + reader.onload = function (e) { + SendE2e(e.target.result, recipientContactFile, myContactFileName, statePath, statePass); + }; + reader.readAsText(e.target.files[0]); + }, false); + }); + </script> +</head> +<body> +<h1>Receiver</h1> +<form id="start-cmix"> + <div> + <label for="ndf-input">Select NDF file to use <code>ndf</code> variable in JS (required):</label><br/> + <input type="file" id="ndf-input" required/> + </div> + <!-- <div> + <label for="recipient-contact-input">Recipient contact path (optional):</label><br/> + <input type="file" id="recipient-contact-input"/> + </div> + <div> + <label for="session-path">Session path (required):</label><br/> + <input type="text" id="session-path" required/> + </div> + <div> + <label for="session-password">Storage password (required):</label><br/> + <input type="text" id="session-password" required/> + </div> + <input type="submit" value="Start">--> +</form> +<div id="output" style="padding:10px;border:1px solid red"></div> +</body> + +<script> +</script> +</html> \ No newline at end of file diff --git a/examples/sendE2E/index2.html b/examples/sendE2E/index2.html new file mode 100644 index 0000000000000000000000000000000000000000..6665b33c9a44dab1e5974de6d742e075d92c2270 --- /dev/null +++ b/examples/sendE2E/index2.html @@ -0,0 +1,61 @@ +<!-- + ~ Copyright © 2020 xx network SEZC /// + ~ /// + ~ Use of this source code is governed by a license that can be found in the /// + ~ LICENSE file /// + --> + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Sender</title> + + <link rel="stylesheet" type="text/css" href="../styles.css"> + <link rel="shortcut icon" type="image/x-icon" href="sender-favicon.ico" /> + <script type="text/javascript" src="xxdk.js"></script> + <script type="text/javascript" src="../wasm_exec.js"></script> + <script> + // Use the encoder to convert a string to Uint8Array using enc.encode() + + const go = new Go(); + WebAssembly.instantiateStreaming(fetch("../xxdk.wasm"), go.importObject).then((result) => { + go.run(result.instance); + + LogLevel(0); + + const recipientContactFile = '<xxc(2)Q2uq69ry88AeNFKcnpOkCjuCtkYIdv/fgC3F4z6eNUMDrgZ7Ugdw/BAr6bG0KyMpEOL6fulH331JBFOD69e7iZLxkBr3BvZyfyTXL9QtQwpzaDnmPXjyRR5cjAQ6gfk5XQzsrw45Q8qsrKewwZsqGhac0NKJYPiXGa9DTQR6f1VMOY7cco4uquNN5BRo4ucz1gu9w2Ff3N+1Hdz9V1r7xulkkd/78IyoJqHQDgp1eO3q6NZJT55DNsSuS2ZuYQc3yQUyTHH/G7gIF7EwRTU6dhRTGMYpfOQhRT67EVidHOT4e7GSpkWoGzi5XUBA+9N1llRCAwzRJ65lQqJZIC/vNgxJhHR5Cd4AOfHc+KuGlXMpCQkeYjd7a+ggh4RUuPsMW59QlKaBbZ1mbGHPzphFUrJIS63TMcJRrWbGwXHJrvZnD1NYNOM/x/qSR4pTkv8soIHFzgvFbRME5VTfxWfWKSCG/qu3TaWfetnYXmsqhdmnURekF4iSMtyDpVch+86zK5YmuO9Ap18MvdwmnfX5r9xhyPRga/QqmkdEI6ZebuXVYJQGr6Lzsz4z+4AGI0v87j//APsGxvi8fwAAAgA7w6N/pgZWFlB+p/Muirk+VQ==xxc>'; + const myContactFileName = 'theirE2eContact.xxc'; + const statePath = 'statePathSender'; + const statePass = 'password'; + + document.getElementById('ndf-input') + .addEventListener('change', function (e) { + let reader = new FileReader(); + reader.onload = function (e) { + SendE2e(e.target.result, recipientContactFile, myContactFileName, statePath, statePass); + }; + reader.readAsText(e.target.files[0]); + }, false); + }); + </script> +</head> +<body> +<h1>Sender</h1> +<form id="start-cmix"> + <div> + <label for="ndf-input">Select NDF file to use <code>ndf</code> variable in JS:</label><br/> + <input type="file" id="ndf-input" required/> + </div> +<!-- <div> + <label for="ndf-input">Recipient contact path:</label><br/> + <input type="file" id="recipient-contact-input" required/> + </div> + <input type="submit" value="Start">--> +</form> +<div id="output" style="padding:10px;border:1px solid red"></div> +</body> + +<script> +</script> +</html> \ No newline at end of file diff --git a/examples/sendE2E/receiver-favicon.ico b/examples/sendE2E/receiver-favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a7b5826dfdad175084ea63406202334dfe29bf4 Binary files /dev/null and b/examples/sendE2E/receiver-favicon.ico differ diff --git a/examples/sendE2E/sender-favicon.ico b/examples/sendE2E/sender-favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..149d6cb2fdb5e20b4a4f80a5797878f73e14d25e Binary files /dev/null and b/examples/sendE2E/sender-favicon.ico differ diff --git a/examples/sendE2E/xxdk.js b/examples/sendE2E/xxdk.js new file mode 100644 index 0000000000000000000000000000000000000000..533eead2b67038e3fbc4d16c13cdca758a3da86f --- /dev/null +++ b/examples/sendE2E/xxdk.js @@ -0,0 +1,248 @@ +/* + * Copyright © 2020 xx network SEZC /// + * /// + * Use of this source code is governed by a license that can be found in the /// + * LICENSE file /// + */ + +async function SendE2e(ndf, recipientContactFile, myContactFileName, statePath, statePassString) { + let enc = new TextEncoder(); + let dec = new TextDecoder(); + + const output = document.getElementById("output") + const statePass = enc.encode(statePassString); + + // Check if state exists + if (localStorage.getItem(statePath) === null) { + console.log('getting key ' + statePath + ' returned null; making new cmix'); + + output.innerHTML += "Loading new storage\n" + + // Initialize the state + NewCmix(ndf, statePath, statePass, ''); + } + + + //////////////////////////////////////////////////////////////////////////// + // Login to your client session // + //////////////////////////////////////////////////////////////////////////// + + // Login with the same statePath and statePass used to call NewCmix + let netID = LoadCmix(statePath, statePass, GetDefaultCMixParams()); + console.log("LoadCmix() " + netID) + + console.log("sleep start") + await sleep(3000) + console.log("sleep end") + + let net = GetLoadCmix(netID) + console.log("loaded cmix: " + net) + + // Get reception identity (automatically created if one does not exist) + const identityStorageKey = "identityStorageKey"; + let identity; + try { + identity = LoadReceptionIdentity(identityStorageKey, net.GetID()); + } catch { + // If no extant xxdk.ReceptionIdentity, generate and store a new one + identity = net.MakeReceptionIdentity(); + + StoreReceptionIdentity(identityStorageKey, identity, net.GetID()); + } + + // Print contact to console. This should probably save a file. + const myContactFile = dec.decode(GetContactFromReceptionIdentity(identity)) + console.log("my contact file content: " + myContactFile); + + // Start file download. + download(myContactFileName, myContactFile); + + let confirm = false; + let confirmContact; + let e2eClient; + let authCallbacks = { + Confirm: function (contact, receptionId, ephemeralId, roundId) { + confirm = true; + confirmContact = contact + console.log("Confirm:"); + console.log("contact: " + dec.decode(contact)); + console.log("receptionId: " + ephemeralId.toString()); + console.log("ephemeralId: " + roundId.toString()); + + output.innerHTML += "Received confirmation from " + ephemeralId.toString() + "<br />" + }, + Request: function (contact, receptionId, ephemeralId, roundId) { + console.log("Request:"); + console.log("contact: " + dec.decode(contact)); + console.log("receptionId: " + ephemeralId.toString()); + console.log("ephemeralId: " + roundId.toString()); + + e2eClient.Confirm(contact) + output.innerHTML += "Received Request from " + ephemeralId.toString() + "<br />" + } + } + + // Create an E2E client + // Pass in auth object which controls auth callbacks for this client + const params = GetDefaultE2EParams(); + console.log("Using E2E parameters: " + dec.decode(params)); + e2eClient = Login(net.GetID(), authCallbacks, identity, params); + + e2eClient.DeleteAllRequests() + + + //////////////////////////////////////////////////////////////////////////// + // Start network threads // + //////////////////////////////////////////////////////////////////////////// + + // Set networkFollowerTimeout to a value of your choice (seconds) + net.StartNetworkFollower(5000); + + output.innerHTML += "Starting network follower<br />" + + // Provide a callback that will be signalled when network health status changes + let health = false + net.AddHealthCallback({ + Callback: function (healthy) { + health = healthy; + } + }); + await sleep(3000) + + + const n = 100 + for (let i = 0; (health === false) && (i < n); i++) { + await sleep(100) + } + + if (health === false) { + console.error("Continuing with unhealthy network") + output.innerHTML += "Network NOT healthy<br />" + } else { + output.innerHTML += "Network healthy<br />" + } + + + //////////////////////////////////////////////////////////////////////////// + // Register a listener for messages // + //////////////////////////////////////////////////////////////////////////// + + let listener = { + Hear: function (item) { + console.log("Listener heard: " + dec.decode(item)); + output.innerHTML += "Listener heard: " + dec.decode(item) + "<br />" + }, + Name: function () { + return "Listener"; + } + } + + // Listen for all types of messages using catalog.NoType + // Listen for messages from all users using id.ZeroUser + let zerUser = Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]); + e2eClient.RegisterListener(zerUser, 0, listener); + + output.innerHTML += "Registered listener<br />" + + //////////////////////////////////////////////////////////////////////////// + // Connect with the recipient // + //////////////////////////////////////////////////////////////////////////// + + // Check that the partner exists + if (recipientContactFile !== '') { + let exists = false; + output.innerHTML += "getting ID from contact<br />" + const recipientContactID = GetIDFromContact(recipientContactFile); + console.log(typeof recipientContactID) + console.log("recipientContactID: " + recipientContactID) + + output.innerHTML += "Checking for " + recipientContactID + "<br />" + + + const partnerIDS = dec.decode(e2eClient.GetAllPartnerIDs()) + console.log("partnerIDS: " + partnerIDS) + let partners = JSON.parse(partnerIDS); + + for (let i = 0; i < partners.length; i++) { + const partnerBytes = base64ToArrayBuffer(partners[i]) + console.log("partner " + recipientContactID + " == " + i + " " + partnerBytes) + + if (partnerBytes.toString() === recipientContactID.toString()) { + console.log("MATCH! partner " + recipientContactID + " matches partner " + i + " " + partnerBytes) + exists = true; + break + } + } + + // If the partner does not exist, send a request + if (exists === false) { + output.innerHTML += "Partner does not exist, Request sent to " + recipientContactID + "<br />" + const factList = enc.encode('[]') + e2eClient.Request(enc.encode(recipientContactFile), factList) + + for (let i = 0; (i < 600) && (confirm === false); i++) { + await sleep(50) + } + if (confirm === false) { + output.innerHTML += "Checking for " + recipientContactIDBase64 + "<br />" + console.error(new Error("timed out waiting for confirmation")) + } + + const confirmContactID = GetIDFromContact(confirmContact) + if (recipientContactID.toString() !== confirmContactID.toString()) { + throw new Error("contact ID from confirmation " + + btoa(dec.decode(confirmContactID)) + + " does not match recipient ID " + + recipientContactIDBase64) + } + } else { + output.innerHTML += "Partner exists<br />" + } + + //////////////////////////////////////////////////////////////////////////// + // Send a message to the recipient // + //////////////////////////////////////////////////////////////////////////// + + // Test message + const msgBody = "If this message is sent successfully, we'll have established contact with the recipient." + + output.innerHTML += "Sending E2E message<br />" + // const paramsObj = JSON.parse(dec.decode(params)) + // const e2eParams = JSON.stringify(paramsObj.Base) + // console.log("e2eParams: " + e2eParams) + const e2eSendReport = e2eClient.SendE2E(2, recipientContactID, enc.encode(msgBody), params) + + console.log("e2e send report: " + dec.decode(e2eSendReport)) + output.innerHTML += "Send e2e: " + dec.decode(e2eSendReport) + "<br />" + } else { + output.innerHTML += "Partner does not exist<br />" + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +function download(filename, text) { + let element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +} + +function base64ToArrayBuffer(base64) { + const binary_string = window.atob(base64); + const len = binary_string.length; + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; +} \ No newline at end of file diff --git a/examples/styles.css b/examples/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..802a6a38cc0fcaab7f49dc0312a05fe63f8c11c5 --- /dev/null +++ b/examples/styles.css @@ -0,0 +1,82 @@ +/* + * Copyright © 2020 xx network SEZC /// + * /// + * Use of this source code is governed by a license that can be found in the /// + * LICENSE file /// + */ + +/****************************************************************************** + * Copyright © 2022 xx foundation * + * * + * Use of this source code is governed by a license that can be found in the * + * LICENSE file. * + ******************************************************************************/ + +/****************************************************************************** + * CSS Reset (meyerweb reset, v2.0 | 20110126) * + ******************************************************************************/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +/****************************************************************************** + * Global Styles * + ******************************************************************************/ +body { + font-family: "Roboto", "Franklin Gothic Medium", Tahoma, sans-serif; +} + +form { + margin:1em; +} + +form div { + margin:1em 0; +} \ No newline at end of file diff --git a/examples/wasm_exec.js b/examples/wasm_exec.js new file mode 100644 index 0000000000000000000000000000000000000000..bba4a84051b5fb6bf284df03d21556eb56500062 --- /dev/null +++ b/examples/wasm_exec.js @@ -0,0 +1,650 @@ +/* + * Copyright © 2020 xx network SEZC /// + * /// + * Use of this source code is governed by a license that can be found in the /// + * LICENSE file /// + */ + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +(() => { + // Map multiple JavaScript environments to a single common API, + // preferring web standards over Node.js API. + // + // Environments considered: + // - Browsers + // - Node.js + // - Electron + // - Parcel + // - Webpack + + if (typeof global !== "undefined") { + // global already exists + } else if (typeof window !== "undefined") { + window.global = window; + } else if (typeof self !== "undefined") { + self.global = self; + } else { + throw new Error("cannot export Go (neither global, window nor self is defined)"); + } + + if (!global.require && typeof require !== "undefined") { + global.require = require; + } + + if (!global.fs && global.require) { + const fs = require("fs"); + if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) { + global.fs = fs; + } + } + + const enosys = () => { + const err = new Error("not implemented"); + err.code = "ENOSYS"; + return err; + }; + + if (!global.fs) { + let outputBuf = ""; + global.fs = { + constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused + writeSync(fd, buf) { + outputBuf += decoder.decode(buf); + const nl = outputBuf.lastIndexOf("\n"); + if (nl != -1) { + console.log(outputBuf.substr(0, nl)); + outputBuf = outputBuf.substr(nl + 1); + } + return buf.length; + }, + write(fd, buf, offset, length, position, callback) { + if (offset !== 0 || length !== buf.length || position !== null) { + callback(enosys()); + return; + } + const n = this.writeSync(fd, buf); + callback(null, n); + }, + chmod(path, mode, callback) { callback(enosys()); }, + chown(path, uid, gid, callback) { callback(enosys()); }, + close(fd, callback) { callback(enosys()); }, + fchmod(fd, mode, callback) { callback(enosys()); }, + fchown(fd, uid, gid, callback) { callback(enosys()); }, + fstat(fd, callback) { callback(enosys()); }, + fsync(fd, callback) { callback(null); }, + ftruncate(fd, length, callback) { callback(enosys()); }, + lchown(path, uid, gid, callback) { callback(enosys()); }, + link(path, link, callback) { callback(enosys()); }, + lstat(path, callback) { callback(enosys()); }, + mkdir(path, perm, callback) { callback(enosys()); }, + open(path, flags, mode, callback) { callback(enosys()); }, + read(fd, buffer, offset, length, position, callback) { callback(enosys()); }, + readdir(path, callback) { callback(enosys()); }, + readlink(path, callback) { callback(enosys()); }, + rename(from, to, callback) { callback(enosys()); }, + rmdir(path, callback) { callback(enosys()); }, + stat(path, callback) { callback(enosys()); }, + symlink(path, link, callback) { callback(enosys()); }, + truncate(path, length, callback) { callback(enosys()); }, + unlink(path, callback) { callback(enosys()); }, + utimes(path, atime, mtime, callback) { callback(enosys()); }, + }; + } + + if (!global.process) { + global.process = { + getuid() { return -1; }, + getgid() { return -1; }, + geteuid() { return -1; }, + getegid() { return -1; }, + getgroups() { throw enosys(); }, + pid: -1, + ppid: -1, + umask() { throw enosys(); }, + cwd() { throw enosys(); }, + chdir() { throw enosys(); }, + } + } + + if (!global.crypto && global.require) { + const nodeCrypto = require("crypto"); + global.crypto = { + getRandomValues(b) { + nodeCrypto.randomFillSync(b); + }, + }; + } + if (!global.crypto) { + throw new Error("global.crypto is not available, polyfill required (getRandomValues only)"); + } + + if (!global.performance) { + global.performance = { + now() { + const [sec, nsec] = process.hrtime(); + return sec * 1000 + nsec / 1000000; + }, + }; + } + + if (!global.TextEncoder && global.require) { + global.TextEncoder = require("util").TextEncoder; + } + if (!global.TextEncoder) { + throw new Error("global.TextEncoder is not available, polyfill required"); + } + + if (!global.TextDecoder && global.require) { + global.TextDecoder = require("util").TextDecoder; + } + if (!global.TextDecoder) { + throw new Error("global.TextDecoder is not available, polyfill required"); + } + + // End of polyfills for common API. + + const encoder = new TextEncoder("utf-8"); + const decoder = new TextDecoder("utf-8"); + + global.Go = class { + constructor() { + this.argv = ["js"]; + this.env = {}; + this.exit = (code) => { + if (code !== 0) { + console.warn("exit code:", code); + } + }; + this._exitPromise = new Promise((resolve) => { + this._resolveExitPromise = resolve; + }); + this._pendingEvent = null; + this._scheduledTimeouts = new Map(); + this._nextCallbackTimeoutID = 1; + + const setInt64 = (addr, v) => { + this.mem.setUint32(addr + 0, v, true); + this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true); + } + + const getInt64 = (addr) => { + const low = this.mem.getUint32(addr + 0, true); + const high = this.mem.getInt32(addr + 4, true); + return low + high * 4294967296; + } + + const loadValue = (addr) => { + const f = this.mem.getFloat64(addr, true); + if (f === 0) { + return undefined; + } + if (!isNaN(f)) { + return f; + } + + const id = this.mem.getUint32(addr, true); + return this._values[id]; + } + + const storeValue = (addr, v) => { + const nanHead = 0x7FF80000; + + if (typeof v === "number" && v !== 0) { + if (isNaN(v)) { + this.mem.setUint32(addr + 4, nanHead, true); + this.mem.setUint32(addr, 0, true); + return; + } + this.mem.setFloat64(addr, v, true); + return; + } + + if (v === undefined) { + this.mem.setFloat64(addr, 0, true); + return; + } + + let id = this._ids.get(v); + if (id === undefined) { + id = this._idPool.pop(); + if (id === undefined) { + id = this._values.length; + } + this._values[id] = v; + this._goRefCounts[id] = 0; + this._ids.set(v, id); + } + this._goRefCounts[id]++; + let typeFlag = 0; + switch (typeof v) { + case "object": + if (v !== null) { + typeFlag = 1; + } + break; + case "string": + typeFlag = 2; + break; + case "symbol": + typeFlag = 3; + break; + case "function": + typeFlag = 4; + break; + } + this.mem.setUint32(addr + 4, nanHead | typeFlag, true); + this.mem.setUint32(addr, id, true); + } + + const loadSlice = (addr) => { + const array = getInt64(addr + 0); + const len = getInt64(addr + 8); + return new Uint8Array(this._inst.exports.mem.buffer, array, len); + } + + const loadSliceOfValues = (addr) => { + const array = getInt64(addr + 0); + const len = getInt64(addr + 8); + const a = new Array(len); + for (let i = 0; i < len; i++) { + a[i] = loadValue(array + i * 8); + } + return a; + } + + const loadString = (addr) => { + const saddr = getInt64(addr + 0); + const len = getInt64(addr + 8); + return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); + } + + const timeOrigin = Date.now() - performance.now(); + this.importObject = { + go: { + // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters) + // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported + // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function). + // This changes the SP, thus we have to update the SP used by the imported function. + + // func wasmExit(code int32) + "runtime.wasmExit": (sp) => { + sp >>>= 0; + const code = this.mem.getInt32(sp + 8, true); + this.exited = true; + delete this._inst; + delete this._values; + delete this._goRefCounts; + delete this._ids; + delete this._idPool; + this.exit(code); + }, + + // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) + "runtime.wasmWrite": (sp) => { + sp >>>= 0; + const fd = getInt64(sp + 8); + const p = getInt64(sp + 16); + const n = this.mem.getInt32(sp + 24, true); + fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n)); + }, + + // func resetMemoryDataView() + "runtime.resetMemoryDataView": (sp) => { + sp >>>= 0; + this.mem = new DataView(this._inst.exports.mem.buffer); + }, + + // func nanotime1() int64 + "runtime.nanotime1": (sp) => { + sp >>>= 0; + setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); + }, + + // func walltime() (sec int64, nsec int32) + "runtime.walltime": (sp) => { + sp >>>= 0; + const msec = (new Date).getTime(); + setInt64(sp + 8, msec / 1000); + this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true); + }, + + // func scheduleTimeoutEvent(delay int64) int32 + "runtime.scheduleTimeoutEvent": (sp) => { + sp >>>= 0; + const id = this._nextCallbackTimeoutID; + this._nextCallbackTimeoutID++; + this._scheduledTimeouts.set(id, setTimeout( + () => { + this._resume(); + while (this._scheduledTimeouts.has(id)) { + // for some reason Go failed to register the timeout event, log and try again + // (temporary workaround for https://github.com/golang/go/issues/28975) + console.warn("scheduleTimeoutEvent: missed timeout event"); + this._resume(); + } + }, + getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early + )); + this.mem.setInt32(sp + 16, id, true); + }, + + // func clearTimeoutEvent(id int32) + "runtime.clearTimeoutEvent": (sp) => { + sp >>>= 0; + const id = this.mem.getInt32(sp + 8, true); + clearTimeout(this._scheduledTimeouts.get(id)); + this._scheduledTimeouts.delete(id); + }, + + // func getRandomData(r []byte) + "runtime.getRandomData": (sp) => { + sp >>>= 0; + crypto.getRandomValues(loadSlice(sp + 8)); + }, + + // func finalizeRef(v ref) + "syscall/js.finalizeRef": (sp) => { + sp >>>= 0; + const id = this.mem.getUint32(sp + 8, true); + this._goRefCounts[id]--; + if (this._goRefCounts[id] === 0) { + const v = this._values[id]; + this._values[id] = null; + this._ids.delete(v); + this._idPool.push(id); + } + }, + + // func stringVal(value string) ref + "syscall/js.stringVal": (sp) => { + sp >>>= 0; + storeValue(sp + 24, loadString(sp + 8)); + }, + + // func valueGet(v ref, p string) ref + "syscall/js.valueGet": (sp) => { + sp >>>= 0; + const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16)); + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 32, result); + }, + + // func valueSet(v ref, p string, x ref) + "syscall/js.valueSet": (sp) => { + sp >>>= 0; + Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); + }, + + // func valueDelete(v ref, p string) + "syscall/js.valueDelete": (sp) => { + sp >>>= 0; + Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16)); + }, + + // func valueIndex(v ref, i int) ref + "syscall/js.valueIndex": (sp) => { + sp >>>= 0; + storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); + }, + + // valueSetIndex(v ref, i int, x ref) + "syscall/js.valueSetIndex": (sp) => { + sp >>>= 0; + Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); + }, + + // func valueCall(v ref, m string, args []ref) (ref, bool) + "syscall/js.valueCall": (sp) => { + sp >>>= 0; + try { + const v = loadValue(sp + 8); + const m = Reflect.get(v, loadString(sp + 16)); + const args = loadSliceOfValues(sp + 32); + const result = Reflect.apply(m, v, args); + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 56, result); + this.mem.setUint8(sp + 64, 1); + } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 56, err); + this.mem.setUint8(sp + 64, 0); + } + }, + + // func valueInvoke(v ref, args []ref) (ref, bool) + "syscall/js.valueInvoke": (sp) => { + sp >>>= 0; + try { + const v = loadValue(sp + 8); + const args = loadSliceOfValues(sp + 16); + const result = Reflect.apply(v, undefined, args); + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 40, result); + this.mem.setUint8(sp + 48, 1); + } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 40, err); + this.mem.setUint8(sp + 48, 0); + } + }, + + // func valueNew(v ref, args []ref) (ref, bool) + "syscall/js.valueNew": (sp) => { + sp >>>= 0; + try { + const v = loadValue(sp + 8); + const args = loadSliceOfValues(sp + 16); + const result = Reflect.construct(v, args); + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 40, result); + this.mem.setUint8(sp + 48, 1); + } catch (err) { + sp = this._inst.exports.getsp() >>> 0; // see comment above + storeValue(sp + 40, err); + this.mem.setUint8(sp + 48, 0); + } + }, + + // func valueLength(v ref) int + "syscall/js.valueLength": (sp) => { + sp >>>= 0; + setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); + }, + + // valuePrepareString(v ref) (ref, int) + "syscall/js.valuePrepareString": (sp) => { + sp >>>= 0; + const str = encoder.encode(String(loadValue(sp + 8))); + storeValue(sp + 16, str); + setInt64(sp + 24, str.length); + }, + + // valueLoadString(v ref, b []byte) + "syscall/js.valueLoadString": (sp) => { + sp >>>= 0; + const str = loadValue(sp + 8); + loadSlice(sp + 16).set(str); + }, + + // func valueInstanceOf(v ref, t ref) bool + "syscall/js.valueInstanceOf": (sp) => { + sp >>>= 0; + this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0); + }, + + // func copyBytesToGo(dst []byte, src ref) (int, bool) + "syscall/js.copyBytesToGo": (sp) => { + sp >>>= 0; + const dst = loadSlice(sp + 8); + const src = loadValue(sp + 32); + if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { + this.mem.setUint8(sp + 48, 0); + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + setInt64(sp + 40, toCopy.length); + this.mem.setUint8(sp + 48, 1); + }, + + // func copyBytesToJS(dst ref, src []byte) (int, bool) + "syscall/js.copyBytesToJS": (sp) => { + sp >>>= 0; + const dst = loadValue(sp + 8); + const src = loadSlice(sp + 16); + if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { + this.mem.setUint8(sp + 48, 0); + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + setInt64(sp + 40, toCopy.length); + this.mem.setUint8(sp + 48, 1); + }, + + "debug": (value) => { + console.log(value); + }, + + // func throw(exception string, message string) + 'gitlab.com/elixxir/xxdk-wasm/utils.throw': (sp) => { + const exception = loadString(sp + 8) + const message = loadString(sp + 24) + throw globalThis[exception](message) + }, + } + }; + } + + async run(instance) { + if (!(instance instanceof WebAssembly.Instance)) { + throw new Error("Go.run: WebAssembly.Instance expected"); + } + this._inst = instance; + this.mem = new DataView(this._inst.exports.mem.buffer); + this._values = [ // JS values that Go currently has references to, indexed by reference id + NaN, + 0, + null, + true, + false, + global, + this, + ]; + this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id + this._ids = new Map([ // mapping from JS values to reference ids + [0, 1], + [null, 2], + [true, 3], + [false, 4], + [global, 5], + [this, 6], + ]); + this._idPool = []; // unused ids that have been garbage collected + this.exited = false; // whether the Go program has exited + + // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. + let offset = 4096; + + const strPtr = (str) => { + const ptr = offset; + const bytes = encoder.encode(str + "\0"); + new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes); + offset += bytes.length; + if (offset % 8 !== 0) { + offset += 8 - (offset % 8); + } + return ptr; + }; + + const argc = this.argv.length; + + const argvPtrs = []; + this.argv.forEach((arg) => { + argvPtrs.push(strPtr(arg)); + }); + argvPtrs.push(0); + + const keys = Object.keys(this.env).sort(); + keys.forEach((key) => { + argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); + }); + argvPtrs.push(0); + + const argv = offset; + argvPtrs.forEach((ptr) => { + this.mem.setUint32(offset, ptr, true); + this.mem.setUint32(offset + 4, 0, true); + offset += 8; + }); + + // The linker guarantees global data starts from at least wasmMinDataAddr. + // Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr. + const wasmMinDataAddr = 4096 + 8192; + if (offset >= wasmMinDataAddr) { + throw new Error("total length of command line and environment variables exceeds limit"); + } + + this._inst.exports.run(argc, argv); + if (this.exited) { + this._resolveExitPromise(); + } + await this._exitPromise; + } + + _resume() { + if (this.exited) { + throw new Error("Go program has already exited"); + } + this._inst.exports.resume(); + if (this.exited) { + this._resolveExitPromise(); + } + } + + _makeFuncWrapper(id) { + const go = this; + return function () { + const event = { id: id, this: this, args: arguments }; + go._pendingEvent = event; + go._resume(); + return event.result; + }; + } + } + + if ( + typeof module !== "undefined" && + global.require && + global.require.main === module && + global.process && + global.process.versions && + !global.process.versions.electron + ) { + if (process.argv.length < 3) { + console.error("usage: go_js_wasm_exec [wasm binary] [arguments]"); + process.exit(1); + } + + const go = new Go(); + go.argv = process.argv.slice(2); + go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env); + go.exit = process.exit; + WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { + process.on("exit", (code) => { // Node.js exits if no event handler is pending + if (code === 0 && !go.exited) { + // deadlock, make Go print error and stack traces + go._pendingEvent = { id: 0 }; + go._resume(); + } + }); + return go.run(result.instance); + }).catch((err) => { + console.error(err); + process.exit(1); + }); + } +})(); diff --git a/main.go b/main.go index 3f38c3ed65bfc2d89201e5e4c564dcb5ea617cfb..a3c8678bd5054ffec7fcb10c725b710b5f8121ce 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ package main import ( "fmt" "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "gitlab.com/elixxir/xxdk-wasm/wasm" "os" "syscall/js" @@ -21,6 +22,11 @@ func main() { fmt.Println("Starting xxDK WebAssembly bindings.") fmt.Printf("Client version %s\n", bindings.GetVersion()) + // utils/array.go + js.Global().Set("Uint8ArrayToBase64", js.FuncOf(utils.Uint8ArrayToBase64)) + js.Global().Set("Base64ToUint8Array", js.FuncOf(utils.Base64ToUint8Array)) + js.Global().Set("Uint8ArrayEquals", js.FuncOf(utils.Uint8ArrayEquals)) + // wasm/backup.go js.Global().Set("NewCmixFromBackup", js.FuncOf(wasm.NewCmixFromBackup)) js.Global().Set("InitializeBackup", js.FuncOf(wasm.InitializeBackup)) diff --git a/test/assets/wasm_exec.js b/test/assets/wasm_exec.js index 528d7465484087fe3bfdc3f1cdbe93cb1be859a9..c613dfc656f2799b6b3c922f59003cd3347454a7 100644 --- a/test/assets/wasm_exec.js +++ b/test/assets/wasm_exec.js @@ -503,7 +503,7 @@ }, // func throw(exception string, message string) - 'gitlab.com/elixxir/xxdk-wasm/wasm.throw': (sp) => { + 'gitlab.com/elixxir/xxdk-wasm/utils.throw': (sp) => { const exception = loadString(sp + 8) const message = loadString(sp + 24) throw globalThis[exception](message) diff --git a/utils/array.go b/utils/array.go new file mode 100644 index 0000000000000000000000000000000000000000..9ec8df39d596afd6e9d0297b2073e4f96364ede9 --- /dev/null +++ b/utils/array.go @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package utils + +import ( + "bytes" + "encoding/base64" + "syscall/js" +) + +// Uint8ArrayToBase64 encodes an uint8 array to a base 64 string. +// +// Parameters: +// - args[0] - uint8 array (Uint8Array) +// +// Returns: +// - Base 64 encoded string (string). +func Uint8ArrayToBase64(_ js.Value, args []js.Value) interface{} { + return base64.StdEncoding.EncodeToString(CopyBytesToGo(args[0])) +} + +// Base64ToUint8Array decodes a base 64 encoded string to a Uint8Array. +// +// Parameters: +// - args[0] - base 64 encoded string (string) +// +// Returns: +// - Decoded uint8 array (Uint8Array). +// - Throws TypeError if decoding the string fails. +func Base64ToUint8Array(_ js.Value, args []js.Value) interface{} { + b, err := base64.StdEncoding.DecodeString(args[0].String()) + if err != nil { + Throw(TypeError, err) + } + + return CopyBytesToJS(b) +} + +// Uint8ArrayEquals returns true if the two Uint8Array are equal and false +// otherwise. +// +// Parameters: +// - args[0] - array A (Uint8Array) +// - args[1] - array B (Uint8Array) +// +// Returns: +// - If the two arrays are equal (boolean). +func Uint8ArrayEquals(_ js.Value, args []js.Value) interface{} { + a := CopyBytesToGo(args[0]) + b := CopyBytesToGo(args[1]) + + return bytes.Equal(a, b) +} diff --git a/wasm/utils.go b/utils/errors.go similarity index 55% rename from wasm/utils.go rename to utils/errors.go index 7959879b487f59a53187cde114bd01eeaa6a708a..b599a4480f0fa57505f4a9182da09ff4cc75670c 100644 --- a/wasm/utils.go +++ b/utils/errors.go @@ -1,64 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// Copyright © 2022 xx foundation // +// Copyright © 2022 xx network SEZC // // // // Use of this source code is governed by a license that can be found in the // -// LICENSE file. // +// LICENSE file // //////////////////////////////////////////////////////////////////////////////// -//go:build js && wasm - -package wasm +package utils import ( - "encoding/json" "fmt" - "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" "syscall/js" ) -// CopyBytesToGo copies the Uint8Array stored in the js.Value to []byte. This is -// a wrapper for js.CopyBytesToGo to make it more convenient. -func CopyBytesToGo(src js.Value) []byte { - b := make([]byte, src.Length()) - js.CopyBytesToGo(b, src) - return b -} - -// CopyBytesToJS copies the []byte to a Uint8Array stored in a js.Value. This is -// a wrapper for js.CopyBytesToJS to make it more convenient. -func CopyBytesToJS(src []byte) js.Value { - dst := js.Global().Get("Uint8Array").New(len(src)) - js.CopyBytesToJS(dst, src) - return dst +// JsError converts the error to a Javascript Error. +func JsError(err error) js.Value { + return Error.New(err.Error()) } -// WrapCB wraps a Javascript function in an object so that it can be called -// later with only the arguments and without specifying the function name. -// -// Panics if m is not a function. -func WrapCB(parent js.Value, m string) func(args ...interface{}) js.Value { - if parent.Get(m).Type() != js.TypeFunction { - // Create the error separate from the print so stack trace is printed - err := errors.Errorf("Function %q is not of type %s", m, js.TypeFunction) - jww.FATAL.Panicf("%+v", err) - } - - return func(args ...interface{}) js.Value { - return parent.Call(m, args) - } -} - -// JsonToJS converts a marshalled JSON bytes to a Javascript object. -func JsonToJS(src []byte) js.Value { - var inInterface map[string]interface{} - err := json.Unmarshal(src, &inInterface) - if err != nil { - Throw(TypeError, err) - return js.ValueOf(nil) - } - - return js.ValueOf(inInterface) +// JsTrace converts the error to a Javascript Error that includes the error's +// stack trace. +func JsTrace(err error) js.Value { + return Error.New(fmt.Sprintf("%+v", err)) } // Throw function stub to throws Javascript exceptions. The exception must be diff --git a/utils/errors_test.go b/utils/errors_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6f48e4609a3b33b10941336b332eb0f956ac2611 --- /dev/null +++ b/utils/errors_test.go @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +package utils + +import ( + "github.com/pkg/errors" + "syscall/js" + "testing" +) + +func TestJsError(t *testing.T) { + err := errors.Errorf("test error") + + jsError := JsError(err) + + t.Logf("%+v", jsError) + t.Logf("%+v", jsError.String()) + t.Logf("%+v", js.Error{Value: jsError}) +} + +func TestJsTrace(t *testing.T) { +} + +func TestThrow(t *testing.T) { +} + +func Test_throw(t *testing.T) { +} diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000000000000000000000000000000000000..816f4f67c1d795afbab16dc6b6fc4593cd6d5132 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package utils + +import ( + "encoding/json" + "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" + "syscall/js" +) + +var ( + Error = js.Global().Get("Error") + JSON = js.Global().Get("JSON") + Promise = js.Global().Get("Promise") + Uint8Array = js.Global().Get("Uint8Array") +) + +// CopyBytesToGo copies the Uint8Array stored in the js.Value to []byte. This is +// a wrapper for js.CopyBytesToGo to make it more convenient. +func CopyBytesToGo(src js.Value) []byte { + b := make([]byte, src.Length()) + js.CopyBytesToGo(b, src) + return b +} + +// CopyBytesToJS copies the []byte to a Uint8Array stored in a js.Value. This is +// a wrapper for js.CopyBytesToJS to make it more convenient. +func CopyBytesToJS(src []byte) js.Value { + dst := Uint8Array.New(len(src)) + js.CopyBytesToJS(dst, src) + return dst +} + +// WrapCB wraps a Javascript function in an object so that it can be called +// later with only the arguments and without specifying the function name. +// +// Panics if m is not a function. +func WrapCB(parent js.Value, m string) func(args ...interface{}) js.Value { + if parent.Get(m).Type() != js.TypeFunction { + // Create the error separate from the print so stack trace is printed + err := errors.Errorf("Function %q is not of type %s", m, js.TypeFunction) + jww.FATAL.Panicf("%+v", err) + } + + return func(args ...interface{}) js.Value { + return parent.Call(m, args...) + } +} + +// JsonToJS converts a marshalled JSON bytes to a Javascript object. +func JsonToJS(src []byte) (js.Value, error) { + var inInterface map[string]interface{} + err := json.Unmarshal(src, &inInterface) + if err != nil { + Throw(TypeError, err) + return js.ValueOf(nil), err + } + + return js.ValueOf(inInterface), nil +} + +// JsToJson converts the Javascript value to JSON. +func JsToJson(value js.Value) string { + return JSON.Call("stringify", value).String() +} + +type PromiseFn func(resolve, reject func(args ...interface{}) js.Value) + +// CreatePromise creates a Javascript promise to return the value of a blocking +// Go function to Javascript. +func CreatePromise(f PromiseFn) interface{} { + // Create handler for promise (this will be a Javascript function) + handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + // Spawn a new go routine to perform the blocking function + go func(resolve, reject js.Value) { + f(resolve.Invoke, reject.Invoke) + }(args[0], args[1]) + + return nil + }) + + // Create and return the Promise object + return Promise.New(handler) +} diff --git a/wasm/wasm_js.s b/utils/utils_js.s similarity index 100% rename from wasm/wasm_js.s rename to utils/utils_js.s diff --git a/wasm/authenticatedConnection.go b/wasm/authenticatedConnection.go index ca170f49f9e875561248fc046c70f0aaf48a4d7b..d462797ac75f329c6efdcc4b0964215aa9139d7e 100644 --- a/wasm/authenticatedConnection.go +++ b/wasm/authenticatedConnection.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -49,13 +50,13 @@ func (ac *AuthenticatedConnection) IsAuthenticated(js.Value, []js.Value) interfa // - Javascript representation of the Connection object // - throws a TypeError if creating loading the parameters or connecting fails func (c *Cmix) ConnectWithAuthentication(_ js.Value, args []js.Value) interface{} { - recipientContact := CopyBytesToGo(args[1]) - e2eParamsJSON := CopyBytesToGo(args[2]) + recipientContact := utils.CopyBytesToGo(args[1]) + e2eParamsJSON := utils.CopyBytesToGo(args[2]) ac, err := c.api.ConnectWithAuthentication( args[0].Int(), recipientContact, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/backup.go b/wasm/backup.go index c3bfba7e0fa4d762a2dfcd30cc312e9c9a5178f3..ca3072c0105ffc87b170fe3d71aaeb21ea27bde9 100644 --- a/wasm/backup.go +++ b/wasm/backup.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -44,7 +45,7 @@ type updateBackupFunc struct { } func (ubf *updateBackupFunc) UpdateBackup(encryptedBackup []byte) { - ubf.updateBackup(CopyBytesToJS(encryptedBackup)) + ubf.updateBackup(utils.CopyBytesToJS(encryptedBackup)) } //////////////////////////////////////////////////////////////////////////////// @@ -69,17 +70,17 @@ func NewCmixFromBackup(_ js.Value, args []js.Value) interface{} { ndfJSON := args[0].String() storageDir := args[1].String() backupPassphrase := args[2].String() - sessionPassword := CopyBytesToGo(args[3]) - backupFileContents := CopyBytesToGo(args[4]) + sessionPassword := utils.CopyBytesToGo(args[3]) + backupFileContents := utils.CopyBytesToGo(args[4]) report, err := bindings.NewCmixFromBackup(ndfJSON, storageDir, backupPassphrase, sessionPassword, backupFileContents) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } //////////////////////////////////////////////////////////////////////////////// @@ -101,11 +102,11 @@ func NewCmixFromBackup(_ js.Value, args []js.Value) interface{} { // - Javascript representation of the Backup object // - Throws a TypeError if initializing the Backup fails. func InitializeBackup(_ js.Value, args []js.Value) interface{} { - cb := &updateBackupFunc{WrapCB(args[3], "UpdateBackup")} + cb := &updateBackupFunc{utils.WrapCB(args[3], "UpdateBackup")} api, err := bindings.InitializeBackup( args[0].Int(), args[1].Int(), args[2].String(), cb) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -130,10 +131,10 @@ func InitializeBackup(_ js.Value, args []js.Value) interface{} { // - Javascript representation of the Backup object // - Throws a TypeError if initializing the Backup fails. func ResumeBackup(_ js.Value, args []js.Value) interface{} { - cb := &updateBackupFunc{WrapCB(args[2], "UpdateBackup")} + cb := &updateBackupFunc{utils.WrapCB(args[2], "UpdateBackup")} api, err := bindings.ResumeBackup(args[0].Int(), args[1].Int(), cb) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -148,7 +149,7 @@ func ResumeBackup(_ js.Value, args []js.Value) interface{} { func (b *Backup) StopBackup(js.Value, []js.Value) interface{} { err := b.api.StopBackup() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/broadcast.go b/wasm/broadcast.go index df8bd0851594ee39abca5562f82b2f7e6331cfa3..456027b4c63828ac80578ebecc5eea62dea9b7cf 100644 --- a/wasm/broadcast.go +++ b/wasm/broadcast.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -48,11 +49,11 @@ func newChannelJS(api *bindings.Channel) map[string]interface{} { // - Javascript representation of the Channel object. // - Throws a TypeError if creation fails. func NewBroadcastChannel(_ js.Value, args []js.Value) interface{} { - channelDefinition := CopyBytesToGo(args[1]) + channelDefinition := utils.CopyBytesToGo(args[1]) api, err := bindings.NewBroadcastChannel(args[0].Int(), channelDefinition) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -66,7 +67,7 @@ type broadcastListener struct { } func (bl *broadcastListener) Callback(payload []byte, err error) { - bl.callback(CopyBytesToJS(payload), err.Error()) + bl.callback(utils.CopyBytesToJS(payload), err.Error()) } // Listen registers a BroadcastListener for a given method. This allows users to @@ -82,9 +83,9 @@ func (bl *broadcastListener) Callback(payload []byte, err error) { // - Throws a TypeError if registering the listener fails. func (c *Channel) Listen(_ js.Value, args []js.Value) interface{} { err := c.api.Listen( - &broadcastListener{WrapCB(args[0], "Callback")}, args[1].Int()) + &broadcastListener{utils.WrapCB(args[0], "Callback")}, args[1].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -102,13 +103,13 @@ func (c *Channel) Listen(_ js.Value, args []js.Value) interface{} { // Cmix.WaitForRoundResult to see if the broadcast succeeded (Uint8Array). // - Throws a TypeError if broadcasting fails. func (c *Channel) Broadcast(_ js.Value, args []js.Value) interface{} { - report, err := c.api.Broadcast(CopyBytesToGo(args[0])) + report, err := c.api.Broadcast(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // BroadcastAsymmetric sends a given payload over the broadcast channel using @@ -124,13 +125,13 @@ func (c *Channel) Broadcast(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if broadcasting fails. func (c *Channel) BroadcastAsymmetric(_ js.Value, args []js.Value) interface{} { report, err := c.api.BroadcastAsymmetric( - CopyBytesToGo(args[0]), CopyBytesToGo(args[1])) + utils.CopyBytesToGo(args[0]), utils.CopyBytesToGo(args[1])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // MaxPayloadSize returns the maximum possible payload size which can be @@ -159,11 +160,11 @@ func (c *Channel) MaxAsymmetricPayloadSize(js.Value, []js.Value) interface{} { func (c *Channel) Get(js.Value, []js.Value) interface{} { def, err := c.api.Get() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(def) + return utils.CopyBytesToJS(def) } // Stop stops the channel from listening for more messages. diff --git a/wasm/cmix.go b/wasm/cmix.go index 1908b7f6a4ae5a470813e042002dde87bccb09c1..70c2bed182e13601e14a4fc4e9a224bfe7cfcc2f 100644 --- a/wasm/cmix.go +++ b/wasm/cmix.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -74,12 +75,12 @@ func newCmixJS(api *bindings.Cmix) map[string]interface{} { // Returns: // - throws a TypeError if creating new Cmix fails. func NewCmix(_ js.Value, args []js.Value) interface{} { - password := CopyBytesToGo(args[2]) + password := utils.CopyBytesToGo(args[2]) err := bindings.NewCmix( args[0].String(), args[1].String(), password, args[3].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -102,19 +103,23 @@ func NewCmix(_ js.Value, args []js.Value) interface{} { // - args[2] - JSON of [xxdk.CMIXParams] (Uint8Array) // // Returns: -// - Javascript representation of the Cmix object -// - throws a TypeError if creating loading Cmix fails +// - A promise that returns a Javascript representation of the Cmix object. +// - Throws a error if loading Cmix fails. func LoadCmix(_ js.Value, args []js.Value) interface{} { - password := CopyBytesToGo(args[1]) - cmixParamsJSON := CopyBytesToGo(args[2]) - - net, err := bindings.LoadCmix(args[0].String(), password, cmixParamsJSON) - if err != nil { - Throw(TypeError, err) - return nil + storageDir := args[0].String() + password := utils.CopyBytesToGo(args[1]) + cmixParamsJSON := utils.CopyBytesToGo(args[2]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + net, err := bindings.LoadCmix(storageDir, password, cmixParamsJSON) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(newCmixJS(net)) + } } - return newCmixJS(net) + return utils.CreatePromise(promiseFn) } // GetID returns the ID for this [bindings.Cmix] in the cmixTracker. diff --git a/wasm/connect.go b/wasm/connect.go index a3ceda0de48d375299c1aa94fd6ecbaa783f6692..779ff4c9ae37f5f5124af5fe0db4ea12f7aa756b 100644 --- a/wasm/connect.go +++ b/wasm/connect.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -59,11 +60,11 @@ func (c *Connection) GetID(js.Value, []js.Value) interface{} { // - Javascript representation of the Connection object // - throws a TypeError if creating loading the parameters or connecting fails func (c *Cmix) Connect(_ js.Value, args []js.Value) interface{} { - recipientContact := CopyBytesToGo(args[1]) - e2eParamsJSON := CopyBytesToGo(args[2]) + recipientContact := utils.CopyBytesToGo(args[1]) + e2eParamsJSON := utils.CopyBytesToGo(args[2]) api, err := c.api.Connect(args[0].Int(), recipientContact, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -86,12 +87,12 @@ func (c *Cmix) Connect(_ js.Value, args []js.Value) interface{} { // cmix.WaitForRoundResult to see if the send succeeded (Uint8Array) // - throws a TypeError if sending fails func (c *Connection) SendE2E(_ js.Value, args []js.Value) interface{} { - sendReport, err := c.api.SendE2E(args[0].Int(), CopyBytesToGo(args[1])) + sendReport, err := c.api.SendE2E(args[0].Int(), utils.CopyBytesToGo(args[1])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(sendReport) + return utils.CopyBytesToJS(sendReport) } // Close deletes this Connection's partner.Manager and releases resources. @@ -101,7 +102,7 @@ func (c *Connection) SendE2E(_ js.Value, args []js.Value) interface{} { func (c *Connection) Close(js.Value, []js.Value) interface{} { err := c.api.Close() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -113,7 +114,7 @@ func (c *Connection) Close(js.Value, []js.Value) interface{} { // Returns: // - bytes of the partner's [id.ID] (Uint8Array) func (c *Connection) GetPartner(js.Value, []js.Value) interface{} { - return CopyBytesToJS(c.api.GetPartner()) + return utils.CopyBytesToJS(c.api.GetPartner()) } // listener adheres to the [bindings.Listener] interface. @@ -122,7 +123,7 @@ type listener struct { name func(args ...interface{}) js.Value } -func (l *listener) Hear(item []byte) { l.hear(CopyBytesToJS(item)) } +func (l *listener) Hear(item []byte) { l.hear(utils.CopyBytesToJS(item)) } func (l *listener) Name() string { return l.name().String() } // RegisterListener is used for E2E reception and allows for reading data sent @@ -137,9 +138,9 @@ func (l *listener) Name() string { return l.name().String() } // - throws a TypeError is registering the listener fails func (c *Connection) RegisterListener(_ js.Value, args []js.Value) interface{} { err := c.api.RegisterListener(args[0].Int(), - &listener{WrapCB(args[1], "Hear"), WrapCB(args[1], "Name")}) + &listener{utils.WrapCB(args[1], "Hear"), utils.WrapCB(args[1], "Name")}) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/delivery.go b/wasm/delivery.go index d2b8d31efa923ada83881fb4e57c48392018ff14..b0f340978e6a92ccb510bc36c60a8875b309c77f 100644 --- a/wasm/delivery.go +++ b/wasm/delivery.go @@ -10,6 +10,7 @@ package wasm import ( + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -21,7 +22,7 @@ type messageDeliveryCallback struct { func (mdc *messageDeliveryCallback) EventCallback( delivered, timedOut bool, roundResults []byte) { - mdc.eventCallback(delivered, timedOut, CopyBytesToJS(roundResults)) + mdc.eventCallback(delivered, timedOut, utils.CopyBytesToJS(roundResults)) } // WaitForRoundResult allows the caller to get notified if the rounds a message @@ -48,12 +49,12 @@ func (mdc *messageDeliveryCallback) EventCallback( // - throws a TypeError if the parameters are invalid or getting round results // fails func (c *Cmix) WaitForRoundResult(_ js.Value, args []js.Value) interface{} { - roundList := CopyBytesToGo(args[0]) - mdc := &messageDeliveryCallback{WrapCB(args[1], "EventCallback")} + roundList := utils.CopyBytesToGo(args[0]) + mdc := &messageDeliveryCallback{utils.WrapCB(args[1], "EventCallback")} err := c.api.WaitForRoundResult(roundList, mdc, args[2].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/dummy.go b/wasm/dummy.go index 822acd644a2e33632aad75fd369c6cf6a894e8f7..a8400f356be09045da9dcfe3da2234bbd5838fe9 100644 --- a/wasm/dummy.go +++ b/wasm/dummy.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -56,7 +57,7 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) interface{} { dt, err := bindings.NewDummyTrafficManager( args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -80,7 +81,7 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) interface{} { func (dt *DummyTraffic) SetStatus(_ js.Value, args []js.Value) interface{} { err := dt.api.SetStatus(args[0].Bool()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/e2e.go b/wasm/e2e.go index 9ae1551b29e59d70cd968cb41540a7898429e904..70a66436a5b0bad3a5e5544b163e3b0d14c57f38 100644 --- a/wasm/e2e.go +++ b/wasm/e2e.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -91,13 +92,13 @@ func (e *E2e) GetID(js.Value, []js.Value) interface{} { // - Throws a TypeError if logging in fails. func Login(_ js.Value, args []js.Value) interface{} { callbacks := newAuthCallbacks(args[1]) - identity := CopyBytesToGo(args[2]) - e2eParamsJSON := CopyBytesToGo(args[3]) + identity := utils.CopyBytesToGo(args[2]) + e2eParamsJSON := utils.CopyBytesToGo(args[3]) newE2E, err := bindings.Login( args[0].Int(), callbacks, identity, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -121,13 +122,13 @@ func Login(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if logging in fails. func LoginEphemeral(_ js.Value, args []js.Value) interface{} { callbacks := newAuthCallbacks(args[1]) - identity := CopyBytesToGo(args[2]) - e2eParamsJSON := CopyBytesToGo(args[3]) + identity := utils.CopyBytesToGo(args[2]) + e2eParamsJSON := utils.CopyBytesToGo(args[3]) newE2E, err := bindings.LoginEphemeral( args[0].Int(), callbacks, identity, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -139,7 +140,7 @@ func LoginEphemeral(_ js.Value, args []js.Value) interface{} { // Returns: // - Marshalled [contact.Contact] (Uint8Array) func (e *E2e) GetContact(js.Value, []js.Value) interface{} { - return CopyBytesToJS(e.api.GetContact()) + return utils.CopyBytesToJS(e.api.GetContact()) } // GetUdAddressFromNdf retrieve the User Discovery's network address fom the @@ -156,7 +157,7 @@ func (e *E2e) GetUdAddressFromNdf(js.Value, []js.Value) interface{} { // Returns: // - Public certificate in PEM format (Uint8Array) func (e *E2e) GetUdCertFromNdf(js.Value, []js.Value) interface{} { - return CopyBytesToJS(e.api.GetUdCertFromNdf()) + return utils.CopyBytesToJS(e.api.GetUdCertFromNdf()) } // GetUdContactFromNdf assembles the User Discovery's contact file from the data @@ -168,11 +169,11 @@ func (e *E2e) GetUdCertFromNdf(js.Value, []js.Value) interface{} { func (e *E2e) GetUdContactFromNdf(js.Value, []js.Value) interface{} { b, err := e.api.GetUdContactFromNdf() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(b) + return utils.CopyBytesToJS(b) } //////////////////////////////////////////////////////////////////////////////// @@ -193,15 +194,15 @@ func newAuthCallbacks(value js.Value) *authCallbacks { a := &authCallbacks{} if value.Get("Request").Type() == js.TypeFunction { - a.request = WrapCB(value, "Request") + a.request = utils.WrapCB(value, "Request") } if value.Get("Confirm").Type() == js.TypeFunction { - a.confirm = WrapCB(value, "Confirm") + a.confirm = utils.WrapCB(value, "Confirm") } if value.Get("Reset").Type() == js.TypeFunction { - a.reset = WrapCB(value, "Reset") + a.reset = utils.WrapCB(value, "Reset") } return a @@ -210,20 +211,23 @@ func newAuthCallbacks(value js.Value) *authCallbacks { func (a *authCallbacks) Request( contact, receptionId []byte, ephemeralId, roundId int64) { if a.request != nil { - a.request(contact, receptionId, ephemeralId, roundId) + a.request(utils.CopyBytesToJS(contact), utils.CopyBytesToJS(receptionId), + ephemeralId, roundId) } } func (a *authCallbacks) Confirm( contact, receptionId []byte, ephemeralId, roundId int64) { if a.confirm != nil { - a.confirm(contact, receptionId, ephemeralId, roundId) + a.confirm(utils.CopyBytesToJS(contact), utils.CopyBytesToJS(receptionId), + ephemeralId, roundId) } - } + func (a *authCallbacks) Reset( contact, receptionId []byte, ephemeralId, roundId int64) { if a.reset != nil { - a.reset(contact, receptionId, ephemeralId, roundId) + a.reset(utils.CopyBytesToJS(contact), utils.CopyBytesToJS(receptionId), + ephemeralId, roundId) } } diff --git a/wasm/e2eAuth.go b/wasm/e2eAuth.go index 39158b8d387142f4a4e4b99b7e272b74724b415f..3d6efa4343e7441a51c328e99defa1fb75873625 100644 --- a/wasm/e2eAuth.go +++ b/wasm/e2eAuth.go @@ -10,6 +10,7 @@ package wasm import ( + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -36,18 +37,22 @@ import ( // - args[1] - JSON of [fact.FactList] (Uint8Array). // // Returns: -// - ID of the round (int). -// - Throws TypeError if the request fails. +// - A promise that returns the ID of the round (int). +// - Throws an error if the request fails. func (e *E2e) Request(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) - factsListJson := CopyBytesToGo(args[1]) - rid, err := e.api.Request(partnerContact, factsListJson) - if err != nil { - Throw(TypeError, err) - return nil + partnerContact := utils.CopyBytesToGo(args[0]) + factsListJson := utils.CopyBytesToGo(args[1]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + rid, err := e.api.Request(partnerContact, factsListJson) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(rid) + } } - return rid + return utils.CreatePromise(promiseFn) } // Confirm sends a confirmation for a received request. It can only be called @@ -70,17 +75,21 @@ func (e *E2e) Request(_ js.Value, args []js.Value) interface{} { // - args[0] - marshalled bytes of the partner [contact.Contact] (Uint8Array). // // Returns: -// - ID of the round (int). -// - Throws TypeError if the confirmation fails. +// - A promise that returns the ID of the round (int). +// - Throws an error if the confirmation fails. func (e *E2e) Confirm(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) - rid, err := e.api.Confirm(partnerContact) - if err != nil { - Throw(TypeError, err) - return nil + partnerContact := utils.CopyBytesToGo(args[0]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + rid, err := e.api.Confirm(partnerContact) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(rid) + } } - return rid + return utils.CreatePromise(promiseFn) } // Reset sends a contact reset request from the user identity in the imported @@ -101,17 +110,21 @@ func (e *E2e) Confirm(_ js.Value, args []js.Value) interface{} { // - args[0] - marshalled bytes of the partner [contact.Contact] (Uint8Array). // // Returns: -// - ID of the round (int). -// - Throws TypeError if the reset fails. +// - A promise that returns the ID of the round (int). +// - Throws an error if the reset fails. func (e *E2e) Reset(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) - rid, err := e.api.Reset(partnerContact) - if err != nil { - Throw(TypeError, err) - return nil + partnerContact := utils.CopyBytesToGo(args[0]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + rid, err := e.api.Reset(partnerContact) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(rid) + } } - return rid + return utils.CreatePromise(promiseFn) } // ReplayConfirm resends a confirmation to the partner. It will fail to send if @@ -126,17 +139,21 @@ func (e *E2e) Reset(_ js.Value, args []js.Value) interface{} { // - args[0] - marshalled bytes of the partner [contact.Contact] (Uint8Array). // // Returns: -// - ID of the round (int). -// - Throws TypeError if the confirmation fails. +// - A promise that returns the ID of the round (int). +// - Throws an error if the confirmation fails. func (e *E2e) ReplayConfirm(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) - rid, err := e.api.ReplayConfirm(partnerContact) - if err != nil { - Throw(TypeError, err) - return nil + partnerContact := utils.CopyBytesToGo(args[0]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + rid, err := e.api.ReplayConfirm(partnerContact) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(rid) + } } - return rid + return utils.CreatePromise(promiseFn) } // CallAllReceivedRequests will iterate through all pending contact requests and @@ -154,10 +171,10 @@ func (e *E2e) CallAllReceivedRequests(js.Value, []js.Value) interface{} { // Returns: // - Throws TypeError if the deletion fails. func (e *E2e) DeleteRequest(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) + partnerContact := utils.CopyBytesToGo(args[0]) err := e.api.DeleteRequest(partnerContact) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -171,7 +188,7 @@ func (e *E2e) DeleteRequest(_ js.Value, args []js.Value) interface{} { func (e *E2e) DeleteAllRequests(js.Value, []js.Value) interface{} { err := e.api.DeleteAllRequests() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -185,7 +202,7 @@ func (e *E2e) DeleteAllRequests(js.Value, []js.Value) interface{} { func (e *E2e) DeleteSentRequests(js.Value, []js.Value) interface{} { err := e.api.DeleteSentRequests() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -199,7 +216,7 @@ func (e *E2e) DeleteSentRequests(js.Value, []js.Value) interface{} { func (e *E2e) DeleteReceiveRequests(js.Value, []js.Value) interface{} { err := e.api.DeleteReceiveRequests() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -215,14 +232,14 @@ func (e *E2e) DeleteReceiveRequests(js.Value, []js.Value) interface{} { // - The marshalled bytes of [contact.Contact] (Uint8Array). // - Throws TypeError if getting the received request fails. func (e *E2e) GetReceivedRequest(_ js.Value, args []js.Value) interface{} { - partnerContact := CopyBytesToGo(args[0]) + partnerContact := utils.CopyBytesToGo(args[0]) c, err := e.api.GetReceivedRequest(partnerContact) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(c) + return utils.CopyBytesToJS(c) } // VerifyOwnership checks if the received ownership proof is valid. @@ -236,12 +253,12 @@ func (e *E2e) GetReceivedRequest(_ js.Value, args []js.Value) interface{} { // - Returns true if the ownership is valid (boolean) // - Throws TypeError if loading the parameters fails. func (e *E2e) VerifyOwnership(_ js.Value, args []js.Value) interface{} { - receivedContact := CopyBytesToGo(args[0]) - verifiedContact := CopyBytesToGo(args[1]) + receivedContact := utils.CopyBytesToGo(args[0]) + verifiedContact := utils.CopyBytesToGo(args[1]) isValid, err := e.api.VerifyOwnership( receivedContact, verifiedContact, args[2].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -259,11 +276,11 @@ func (e *E2e) VerifyOwnership(_ js.Value, args []js.Value) interface{} { // Returns: // - Throws TypeError if the [id.ID] cannot be unmarshalled. func (e *E2e) AddPartnerCallback(_ js.Value, args []js.Value) interface{} { - partnerID := CopyBytesToGo(args[0]) + partnerID := utils.CopyBytesToGo(args[0]) callbacks := newAuthCallbacks(args[1]) err := e.api.AddPartnerCallback(partnerID, callbacks) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -279,10 +296,10 @@ func (e *E2e) AddPartnerCallback(_ js.Value, args []js.Value) interface{} { // Returns: // - Throws TypeError if the [id.ID] cannot be unmarshalled. func (e *E2e) DeletePartnerCallback(_ js.Value, args []js.Value) interface{} { - partnerID := CopyBytesToGo(args[0]) + partnerID := utils.CopyBytesToGo(args[0]) err := e.api.DeletePartnerCallback(partnerID) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/e2eHandler.go b/wasm/e2eHandler.go index 57d16f894d1290d3cb9cf78e0e34847f6155c8ab..8d6efc63c5e015936230de093d71cf78c0b9b336 100644 --- a/wasm/e2eHandler.go +++ b/wasm/e2eHandler.go @@ -10,6 +10,7 @@ package wasm import ( + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -18,7 +19,7 @@ import ( // Returns: // - The marshalled bytes of the [id.ID] object (Uint8Array) func (e *E2e) GetReceptionID(js.Value, []js.Value) interface{} { - return CopyBytesToJS(e.api.GetReceptionID()) + return utils.CopyBytesToJS(e.api.GetReceptionID()) } // GetAllPartnerIDs returns a list of all partner IDs that the user has an E2E @@ -30,10 +31,10 @@ func (e *E2e) GetReceptionID(js.Value, []js.Value) interface{} { func (e *E2e) GetAllPartnerIDs(js.Value, []js.Value) interface{} { partnerIDs, err := e.api.GetAllPartnerIDs() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(partnerIDs) + return utils.CopyBytesToJS(partnerIDs) } // PayloadSize returns the max payload size for a partitionable E2E message. @@ -83,10 +84,10 @@ func (e *E2e) FirstPartitionSize(js.Value, []js.Value) interface{} { func (e *E2e) GetHistoricalDHPrivkey(js.Value, []js.Value) interface{} { privKey, err := e.api.GetHistoricalDHPrivkey() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(privKey) + return utils.CopyBytesToJS(privKey) } // GetHistoricalDHPubkey returns the user's marshalled historical DH public key. @@ -98,10 +99,10 @@ func (e *E2e) GetHistoricalDHPrivkey(js.Value, []js.Value) interface{} { func (e *E2e) GetHistoricalDHPubkey(js.Value, []js.Value) interface{} { pubKey, err := e.api.GetHistoricalDHPubkey() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(pubKey) + return utils.CopyBytesToJS(pubKey) } // HasAuthenticatedChannel returns true if an authenticated channel with the @@ -114,9 +115,9 @@ func (e *E2e) GetHistoricalDHPubkey(js.Value, []js.Value) interface{} { // - Existence of authenticated channel (boolean) // - Throws TypeError if unmarshalling the ID or getting the channel fails func (e *E2e) HasAuthenticatedChannel(_ js.Value, args []js.Value) interface{} { - exists, err := e.api.HasAuthenticatedChannel(CopyBytesToGo(args[0])) + exists, err := e.api.HasAuthenticatedChannel(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } return exists @@ -132,7 +133,7 @@ func (e *E2e) HasAuthenticatedChannel(_ js.Value, args []js.Value) interface{} { func (e *E2e) RemoveService(_ js.Value, args []js.Value) interface{} { err := e.api.RemoveService(args[0].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -149,22 +150,26 @@ func (e *E2e) RemoveService(_ js.Value, args []js.Value) interface{} { // - args[3] - JSON [e2e.Params] (Uint8Array) // // Returns: -// - JSON of the [bindings.E2ESendReport], which can be passed into -// Cmix.WaitForRoundResult to see if the send succeeded (Uint8Array) -// - Throws TypeError if sending fails +// - A promise that returns the JSON of the [bindings.E2ESendReport], which can +// be passed into Cmix.WaitForRoundResult to see if the send succeeded +// (Uint8Array). +// - Throws error if sending fails. func (e *E2e) SendE2E(_ js.Value, args []js.Value) interface{} { - recipientId := CopyBytesToGo(args[1]) - payload := CopyBytesToGo(args[2]) - e2eParams := CopyBytesToGo(args[3]) - - sendReport, err := e.api.SendE2E( - args[0].Int(), recipientId, payload, e2eParams) - if err != nil { - Throw(TypeError, err) - return nil + recipientId := utils.CopyBytesToGo(args[1]) + payload := utils.CopyBytesToGo(args[2]) + e2eParams := utils.CopyBytesToGo(args[3]) + + promiseFn := func(resolve, reject func(args ...interface{}) js.Value) { + sendReport, err := e.api.SendE2E( + args[0].Int(), recipientId, payload, e2eParams) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(utils.CopyBytesToJS(sendReport)) + } } - return CopyBytesToJS(sendReport) + return utils.CreatePromise(promiseFn) } // processor wraps Javascript callbacks to adhere to the [bindings.Processor] @@ -176,7 +181,7 @@ type processor struct { func (p *processor) Process( message, receptionId []byte, ephemeralId, roundId int64) { - p.process(CopyBytesToJS(message), CopyBytesToJS(receptionId), ephemeralId, + p.process(utils.CopyBytesToJS(message), utils.CopyBytesToJS(receptionId), ephemeralId, roundId) } @@ -201,11 +206,11 @@ func (p *processor) String() string { // Returns: // - Throws TypeError if registering the service fails func (e *E2e) AddService(_ js.Value, args []js.Value) interface{} { - p := &processor{WrapCB(args[1], "Process"), WrapCB(args[1], "String")} + p := &processor{utils.WrapCB(args[1], "Process"), utils.WrapCB(args[1], "String")} err := e.api.AddService(args[0].String(), p) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -225,12 +230,12 @@ func (e *E2e) AddService(_ js.Value, args []js.Value) interface{} { // Returns: // - Throws TypeError if registering the service fails func (e *E2e) RegisterListener(_ js.Value, args []js.Value) interface{} { - recipientId := CopyBytesToGo(args[0]) - l := &listener{WrapCB(args[2], "Hear"), WrapCB(args[2], "Name")} + recipientId := utils.CopyBytesToGo(args[0]) + l := &listener{utils.WrapCB(args[2], "Hear"), utils.WrapCB(args[2], "Name")} err := e.api.RegisterListener(recipientId, args[1].Int(), l) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/errors.go b/wasm/errors.go index 4aae7fe7ec5709b0dbd7d06f9d93677ebb1186b1..a22cdb4cd6422f309ccc45732df86174667e7ea2 100644 --- a/wasm/errors.go +++ b/wasm/errors.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -51,7 +52,7 @@ func CreateUserFriendlyErrorMessage(_ js.Value, args []js.Value) interface{} { func UpdateCommonErrors(_ js.Value, args []js.Value) interface{} { err := bindings.UpdateCommonErrors(args[0].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/fileTransfer.go b/wasm/fileTransfer.go index 52d4a82c41b8d4ef072800bb601400b1e2108364..1a7d7953f29f42d54f569f75caf6547bce3f4a0c 100644 --- a/wasm/fileTransfer.go +++ b/wasm/fileTransfer.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -55,7 +56,7 @@ type receiveFileCallback struct { } func (rfc *receiveFileCallback) Callback(payload []byte, err error) { - rfc.callback(CopyBytesToJS(payload), err.Error()) + rfc.callback(utils.CopyBytesToJS(payload), err.Error()) } // fileTransferSentProgressCallback wraps Javascript callbacks to adhere to the @@ -66,7 +67,7 @@ type fileTransferSentProgressCallback struct { func (spc *fileTransferSentProgressCallback) Callback( payload []byte, t *bindings.FilePartTracker, err error) { - spc.callback(CopyBytesToJS(payload), newFilePartTrackerJS(t), err.Error()) + spc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t), err.Error()) } // fileTransferReceiveProgressCallback wraps Javascript callbacks to adhere to @@ -77,7 +78,7 @@ type fileTransferReceiveProgressCallback struct { func (rpc *fileTransferReceiveProgressCallback) Callback( payload []byte, t *bindings.FilePartTracker, err error) { - rpc.callback(CopyBytesToJS(payload), newFilePartTrackerJS(t), err.Error()) + rpc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t), err.Error()) } //////////////////////////////////////////////////////////////////////////////// @@ -97,14 +98,14 @@ func (rpc *fileTransferReceiveProgressCallback) Callback( // - Javascript representation of the FileTransfer object. // - Throws a TypeError initialising the file transfer manager fails. func InitFileTransfer(_ js.Value, args []js.Value) interface{} { - rfc := &receiveFileCallback{WrapCB(args[1], "Callback")} - e2eFileTransferParamsJson := CopyBytesToGo(args[2]) - fileTransferParamsJson := CopyBytesToGo(args[3]) + rfc := &receiveFileCallback{utils.WrapCB(args[1], "Callback")} + e2eFileTransferParamsJson := utils.CopyBytesToGo(args[2]) + fileTransferParamsJson := utils.CopyBytesToGo(args[3]) api, err := bindings.InitFileTransfer( args[0].Int(), rfc, e2eFileTransferParamsJson, fileTransferParamsJson) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -126,18 +127,18 @@ func InitFileTransfer(_ js.Value, args []js.Value) interface{} { // - A unique ID for this file transfer (Uint8Array). // - Throws a TypeError if sending fails. func (f *FileTransfer) Send(_ js.Value, args []js.Value) interface{} { - payload := CopyBytesToGo(args[0]) - recipientID := CopyBytesToGo(args[1]) + payload := utils.CopyBytesToGo(args[0]) + recipientID := utils.CopyBytesToGo(args[1]) retry := float32(args[2].Float()) - spc := &fileTransferSentProgressCallback{WrapCB(args[3], "Callback")} + spc := &fileTransferSentProgressCallback{utils.WrapCB(args[3], "Callback")} ftID, err := f.api.Send(payload, recipientID, retry, spc, args[4].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(ftID) + return utils.CopyBytesToJS(ftID) } // Receive returns the full file on the completion of the transfer. It deletes @@ -156,13 +157,13 @@ func (f *FileTransfer) Send(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError the file transfer is incomplete or Receive has already // been called. func (f *FileTransfer) Receive(_ js.Value, args []js.Value) interface{} { - file, err := f.api.Receive(CopyBytesToGo(args[0])) + file, err := f.api.Receive(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(file) + return utils.CopyBytesToJS(file) } // CloseSend deletes a file from the internal storage once a transfer has @@ -178,9 +179,9 @@ func (f *FileTransfer) Receive(_ js.Value, args []js.Value) interface{} { // Returns: // - Throws a TypeError if the file transfer is incomplete. func (f *FileTransfer) CloseSend(_ js.Value, args []js.Value) interface{} { - err := f.api.CloseSend(CopyBytesToGo(args[0])) + err := f.api.CloseSend(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -208,12 +209,12 @@ func (f *FileTransfer) CloseSend(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if registering the callback fails. func (f *FileTransfer) RegisterSentProgressCallback( _ js.Value, args []js.Value) interface{} { - tidBytes := CopyBytesToGo(args[0]) - spc := &fileTransferSentProgressCallback{WrapCB(args[1], "Callback")} + tidBytes := utils.CopyBytesToGo(args[0]) + spc := &fileTransferSentProgressCallback{utils.WrapCB(args[1], "Callback")} err := f.api.RegisterSentProgressCallback(tidBytes, spc, args[2].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -236,13 +237,13 @@ func (f *FileTransfer) RegisterSentProgressCallback( // - Throws a TypeError if registering the callback fails. func (f *FileTransfer) RegisterReceivedProgressCallback( _ js.Value, args []js.Value) interface{} { - tidBytes := CopyBytesToGo(args[0]) - rpc := &fileTransferReceiveProgressCallback{WrapCB(args[1], "Callback")} + tidBytes := utils.CopyBytesToGo(args[0]) + rpc := &fileTransferReceiveProgressCallback{utils.WrapCB(args[1], "Callback")} err := f.api.RegisterReceivedProgressCallback( tidBytes, rpc, args[2].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/follow.go b/wasm/follow.go index 634ea5ceff23e4043540896fe5392fb0fac06c76..8da6a4d72b192590b0d8e84b861d1804b785940a 100644 --- a/wasm/follow.go +++ b/wasm/follow.go @@ -10,6 +10,7 @@ package wasm import ( + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -55,7 +56,7 @@ import ( func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) interface{} { err := c.api.StartNetworkFollower(args[0].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -73,7 +74,7 @@ func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) interface{} { func (c *Cmix) StopNetworkFollower(js.Value, []js.Value) interface{} { err := c.api.StopNetworkFollower() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -115,11 +116,11 @@ func (c *Cmix) NetworkFollowerStatus(js.Value, []js.Value) interface{} { func (c *Cmix) GetNodeRegistrationStatus(js.Value, []js.Value) interface{} { b, err := c.api.GetNodeRegistrationStatus() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(b) + return utils.CopyBytesToJS(b) } // HasRunningProcessies checks if any background threads are running and returns @@ -163,7 +164,7 @@ func (nhc *networkHealthCallback) Callback(health bool) { nhc.callback(health) } // - Returns a registration ID that can be used to unregister (int) func (c *Cmix) AddHealthCallback(_ js.Value, args []js.Value) interface{} { return c.api.AddHealthCallback( - &networkHealthCallback{WrapCB(args[0], "Callback")}) + &networkHealthCallback{utils.WrapCB(args[0], "Callback")}) } // RemoveHealthCallback removes a health callback using its registration ID. @@ -192,6 +193,6 @@ func (ce *clientError) Report(source, message, trace string) { // - args[0] - Javascript object that has functions that implement the // [bindings.ClientError] interface func (c *Cmix) RegisterClientErrorCallback(_ js.Value, args []js.Value) interface{} { - c.api.RegisterClientErrorCallback(&clientError{WrapCB(args[0], "Report")}) + c.api.RegisterClientErrorCallback(&clientError{utils.WrapCB(args[0], "Report")}) return nil } diff --git a/wasm/group.go b/wasm/group.go index 5158e4658e021289bd4155976d0fd638be71dd3f..d19da538da36abca4fde43c428529976f6b97eba 100644 --- a/wasm/group.go +++ b/wasm/group.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -55,13 +56,13 @@ func newGroupChatJS(api *bindings.GroupChat) map[string]interface{} { // - Javascript representation of the GroupChat object. // - Throws a TypeError if creating the GroupChat fails. func NewGroupChat(_ js.Value, args []js.Value) interface{} { - requestFunc := &groupRequest{WrapCB(args[1], "Callback")} + requestFunc := &groupRequest{utils.WrapCB(args[1], "Callback")} p := &groupChatProcessor{ - WrapCB(args[2], "Process"), WrapCB(args[2], "String")} + utils.WrapCB(args[2], "Process"), utils.WrapCB(args[2], "String")} api, err := bindings.NewGroupChat(args[0].Int(), requestFunc, p) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -87,17 +88,17 @@ func NewGroupChat(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if making the group fails. func (g *GroupChat) MakeGroup(_ js.Value, args []js.Value) interface{} { // (membershipBytes, message, name []byte) ([]byte, error) - membershipBytes := CopyBytesToGo(args[0]) - message := CopyBytesToGo(args[1]) - name := CopyBytesToGo(args[2]) + membershipBytes := utils.CopyBytesToGo(args[0]) + message := utils.CopyBytesToGo(args[1]) + name := utils.CopyBytesToGo(args[2]) report, err := g.api.MakeGroup(membershipBytes, message, name) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // ResendRequest resends a group request to all members in the group. @@ -112,13 +113,13 @@ func (g *GroupChat) MakeGroup(_ js.Value, args []js.Value) interface{} { // succeeded. // - Throws a TypeError if resending the request fails. func (g *GroupChat) ResendRequest(_ js.Value, args []js.Value) interface{} { - report, err := g.api.ResendRequest(CopyBytesToGo(args[0])) + report, err := g.api.ResendRequest(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // JoinGroup allows a user to join a group when a request is received. @@ -134,7 +135,7 @@ func (g *GroupChat) ResendRequest(_ js.Value, args []js.Value) interface{} { func (g *GroupChat) JoinGroup(_ js.Value, args []js.Value) interface{} { err := g.api.JoinGroup(args[0].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -150,9 +151,9 @@ func (g *GroupChat) JoinGroup(_ js.Value, args []js.Value) interface{} { // Returns: // - Throws a TypeError if leaving the group fails. func (g *GroupChat) LeaveGroup(_ js.Value, args []js.Value) interface{} { - err := g.api.LeaveGroup(CopyBytesToGo(args[0])) + err := g.api.LeaveGroup(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -173,16 +174,16 @@ func (g *GroupChat) LeaveGroup(_ js.Value, args []js.Value) interface{} { // - JSON of [bindings.GroupSendReport] (Uint8Array), which can be passed into // Cmix.WaitForRoundResult to see if the group message send succeeded. func (g *GroupChat) Send(_ js.Value, args []js.Value) interface{} { - groupId := CopyBytesToGo(args[0]) - message := CopyBytesToGo(args[1]) + groupId := utils.CopyBytesToGo(args[0]) + message := utils.CopyBytesToGo(args[1]) report, err := g.api.Send(groupId, message, args[2].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // GetGroups returns a list of group IDs that the user is a member of. @@ -194,11 +195,11 @@ func (g *GroupChat) GetGroups(js.Value, []js.Value) interface{} { // () ([]byte, error) groups, err := g.api.GetGroups() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(groups) + return utils.CopyBytesToJS(groups) } // GetGroup returns the group with the group ID. If no group exists, then the @@ -212,9 +213,9 @@ func (g *GroupChat) GetGroups(js.Value, []js.Value) interface{} { // - Javascript representation of the Group object. // - Throws a TypeError if getting the group fails func (g *GroupChat) GetGroup(_ js.Value, args []js.Value) interface{} { - grp, err := g.api.GetGroup(CopyBytesToGo(args[0])) + grp, err := g.api.GetGroup(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -262,7 +263,7 @@ func newGroupJS(api *bindings.Group) map[string]interface{} { // Returns: // - Uint8Array func (g *Group) GetName(js.Value, []js.Value) interface{} { - return CopyBytesToJS(g.api.GetName()) + return utils.CopyBytesToJS(g.api.GetName()) } // GetID return the 33-byte unique group ID. This represents the id.ID object. @@ -270,7 +271,7 @@ func (g *Group) GetName(js.Value, []js.Value) interface{} { // Returns: // - Uint8Array func (g *Group) GetID(js.Value, []js.Value) interface{} { - return CopyBytesToJS(g.api.GetID()) + return utils.CopyBytesToJS(g.api.GetID()) } // GetTrackedID returns the tracked ID of the Group object. This is used by the @@ -287,7 +288,7 @@ func (g *Group) GetTrackedID(js.Value, []js.Value) interface{} { // Returns: // - Uint8Array func (g *Group) GetInitMessage(js.Value, []js.Value) interface{} { - return CopyBytesToJS(g.api.GetInitMessage()) + return utils.CopyBytesToJS(g.api.GetInitMessage()) } // GetCreatedNano returns the time the group was created in nanoseconds. This is @@ -318,11 +319,11 @@ func (g *Group) GetCreatedMS(js.Value, []js.Value) interface{} { func (g *Group) GetMembership(js.Value, []js.Value) interface{} { membership, err := g.api.GetMembership() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(membership) + return utils.CopyBytesToJS(membership) } // Serialize serializes the Group. @@ -330,7 +331,7 @@ func (g *Group) GetMembership(js.Value, []js.Value) interface{} { // Returns: // - Byte representation of the Group (Uint8Array). func (g *Group) Serialize(js.Value, []js.Value) interface{} { - return CopyBytesToJS(g.api.Serialize()) + return utils.CopyBytesToJS(g.api.Serialize()) } //////////////////////////////////////////////////////////////////////////////// @@ -356,8 +357,8 @@ type groupChatProcessor struct { func (gcp *groupChatProcessor) Process(decryptedMessage, msg, receptionId []byte, ephemeralId, roundId int64, err error) { - gcp.callback(CopyBytesToJS(decryptedMessage), CopyBytesToJS(msg), - CopyBytesToJS(receptionId), ephemeralId, roundId, err.Error()) + gcp.callback(utils.CopyBytesToJS(decryptedMessage), utils.CopyBytesToJS(msg), + utils.CopyBytesToJS(receptionId), ephemeralId, roundId, err.Error()) } func (gcp *groupChatProcessor) String() string { diff --git a/wasm/identity.go b/wasm/identity.go index eb8fadf47b0a8d9fe14e847a1a922ab7f2429c7e..c94de98d55f6352a9846871f74afb9e3b870944e 100644 --- a/wasm/identity.go +++ b/wasm/identity.go @@ -12,6 +12,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" "gitlab.com/elixxir/client/xxdk" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -32,12 +33,12 @@ import ( // Returns: // - throws a TypeError if the identity cannot be stored in storage func StoreReceptionIdentity(_ js.Value, args []js.Value) interface{} { - identity := CopyBytesToGo(args[1]) + identity := utils.CopyBytesToGo(args[1]) err := bindings.StoreReceptionIdentity( args[0].String(), identity, args[2].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -57,11 +58,11 @@ func StoreReceptionIdentity(_ js.Value, args []js.Value) interface{} { func LoadReceptionIdentity(_ js.Value, args []js.Value) interface{} { ri, err := bindings.LoadReceptionIdentity(args[0].String(), args[1].Int()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(ri) + return utils.CopyBytesToJS(ri) } // MakeReceptionIdentity generates a new cryptographic identity for receiving @@ -73,11 +74,11 @@ func LoadReceptionIdentity(_ js.Value, args []js.Value) interface{} { func (c *Cmix) MakeReceptionIdentity(js.Value, []js.Value) interface{} { ri, err := c.api.MakeReceptionIdentity() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(ri) + return utils.CopyBytesToJS(ri) } // MakeLegacyReceptionIdentity generates the legacy identity for receiving @@ -89,11 +90,11 @@ func (c *Cmix) MakeReceptionIdentity(js.Value, []js.Value) interface{} { func (c *Cmix) MakeLegacyReceptionIdentity(js.Value, []js.Value) interface{} { ri, err := c.api.MakeLegacyReceptionIdentity() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(ri) + return utils.CopyBytesToJS(ri) } // GetReceptionRegistrationValidationSignature returns the signature provided by @@ -103,7 +104,7 @@ func (c *Cmix) MakeLegacyReceptionIdentity(js.Value, []js.Value) interface{} { // - signature (Uint8Array) func (c *Cmix) GetReceptionRegistrationValidationSignature( js.Value, []js.Value) interface{} { - return CopyBytesToJS(c.api.GetReceptionRegistrationValidationSignature()) + return utils.CopyBytesToJS(c.api.GetReceptionRegistrationValidationSignature()) } //////////////////////////////////////////////////////////////////////////////// @@ -121,14 +122,14 @@ func (c *Cmix) GetReceptionRegistrationValidationSignature( // - Throws a TypeError if unmarshalling the identity fails func GetContactFromReceptionIdentity(_ js.Value, args []js.Value) interface{} { // Note that this function does not appear in normal bindings - identityJSON := CopyBytesToGo(args[0]) + identityJSON := utils.CopyBytesToGo(args[0]) identity, err := xxdk.UnmarshalReceptionIdentity(identityJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(identity.GetContact().Marshal()) + return utils.CopyBytesToJS(identity.GetContact().Marshal()) } // GetIDFromContact returns the ID in the [contact.Contact] object. @@ -142,11 +143,11 @@ func GetContactFromReceptionIdentity(_ js.Value, args []js.Value) interface{} { func GetIDFromContact(_ js.Value, args []js.Value) interface{} { cID, err := bindings.GetIDFromContact([]byte(args[0].String())) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(cID) + return utils.CopyBytesToJS(cID) } // GetPubkeyFromContact returns the DH public key in the [contact.Contact] @@ -161,11 +162,11 @@ func GetIDFromContact(_ js.Value, args []js.Value) interface{} { func GetPubkeyFromContact(_ js.Value, args []js.Value) interface{} { key, err := bindings.GetPubkeyFromContact([]byte(args[0].String())) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(key) + return utils.CopyBytesToJS(key) } //////////////////////////////////////////////////////////////////////////////// @@ -183,11 +184,11 @@ func GetPubkeyFromContact(_ js.Value, args []js.Value) interface{} { // - marshalled bytes of the modified [contact.Contact] (string) // - throws a TypeError if loading or modifying the contact fails func SetFactsOnContact(_ js.Value, args []js.Value) interface{} { - marshaledContact := CopyBytesToGo(args[0]) - factListJSON := CopyBytesToGo(args[1]) + marshaledContact := utils.CopyBytesToGo(args[0]) + factListJSON := utils.CopyBytesToGo(args[1]) c, err := bindings.SetFactsOnContact(marshaledContact, factListJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -203,11 +204,11 @@ func SetFactsOnContact(_ js.Value, args []js.Value) interface{} { // - JSON of [fact.FactList] (Uint8Array) // - throws a TypeError if loading the contact fails func GetFactsFromContact(_ js.Value, args []js.Value) interface{} { - fl, err := bindings.GetFactsFromContact(CopyBytesToGo(args[0])) + fl, err := bindings.GetFactsFromContact(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(fl) + return utils.CopyBytesToJS(fl) } diff --git a/wasm/logging.go b/wasm/logging.go index 24901db500f2c44bdf63019be0d17e8d65a2d502..e309addce9185edb6ec255abb0ffaf1d34ad12f6 100644 --- a/wasm/logging.go +++ b/wasm/logging.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "io" "log" "syscall/js" @@ -42,7 +43,7 @@ func LogLevel(_ js.Value, args []js.Value) interface{} { level := args[0].Int() if level < 0 || level > 6 { err := errors.Errorf("log level is not valid: log level: %d", level) - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/ndf.go b/wasm/ndf.go index 9f1b3e9f1c56fe0e2ccf72efb0cb47167545cb90..7e00d3d988973c444afef910876cbecc67606fe5 100644 --- a/wasm/ndf.go +++ b/wasm/ndf.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -28,9 +29,9 @@ func DownloadAndVerifySignedNdfWithUrl(_ js.Value, args []js.Value) interface{} ndf, err := bindings.DownloadAndVerifySignedNdfWithUrl( args[0].String(), args[1].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(ndf) + return utils.CopyBytesToJS(ndf) } diff --git a/wasm/params.go b/wasm/params.go index c63d0c7bacc501e9c77b5209bd141b31e83320c8..accafbc3166e80f6d489510e7cc5f9fc0beabae2 100644 --- a/wasm/params.go +++ b/wasm/params.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -21,7 +22,7 @@ import ( // Returns: // - JSON of [xxdk.CMIXParams] (Uint8Array) func GetDefaultCMixParams(js.Value, []js.Value) interface{} { - return CopyBytesToJS(bindings.GetDefaultCMixParams()) + return utils.CopyBytesToJS(bindings.GetDefaultCMixParams()) } // GetDefaultE2EParams returns a JSON serialized object with all of the E2E @@ -31,7 +32,7 @@ func GetDefaultCMixParams(js.Value, []js.Value) interface{} { // Returns: // - JSON of [xxdk.E2EParams] (Uint8Array) func GetDefaultE2EParams(js.Value, []js.Value) interface{} { - return CopyBytesToJS(bindings.GetDefaultE2EParams()) + return utils.CopyBytesToJS(bindings.GetDefaultE2EParams()) } // GetDefaultFileTransferParams returns a JSON serialized object with all the @@ -41,7 +42,7 @@ func GetDefaultE2EParams(js.Value, []js.Value) interface{} { // Returns: // - JSON of [fileTransfer.Params] (Uint8Array) func GetDefaultFileTransferParams(js.Value, []js.Value) interface{} { - return CopyBytesToJS(bindings.GetDefaultFileTransferParams()) + return utils.CopyBytesToJS(bindings.GetDefaultFileTransferParams()) } // GetDefaultSingleUseParams returns a JSON serialized object with all the @@ -51,7 +52,7 @@ func GetDefaultFileTransferParams(js.Value, []js.Value) interface{} { // Returns: // - JSON of [single.RequestParams] (Uint8Array) func GetDefaultSingleUseParams(js.Value, []js.Value) interface{} { - return CopyBytesToJS(bindings.GetDefaultSingleUseParams()) + return utils.CopyBytesToJS(bindings.GetDefaultSingleUseParams()) } // GetDefaultE2eFileTransferParams returns a JSON serialized object with all the @@ -61,5 +62,5 @@ func GetDefaultSingleUseParams(js.Value, []js.Value) interface{} { // Returns: // - JSON of [fileTransfer.e2e.Params] (Uint8Array) func GetDefaultE2eFileTransferParams(js.Value, []js.Value) interface{} { - return CopyBytesToJS(bindings.GetDefaultSingleUseParams()) + return utils.CopyBytesToJS(bindings.GetDefaultSingleUseParams()) } diff --git a/wasm/restlike.go b/wasm/restlike.go index 1833abd1721d580bed12c77ba343c2199d035dab..a12d8ee19b5e6e5501174a88f94ae40ce345f955 100644 --- a/wasm/restlike.go +++ b/wasm/restlike.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -28,17 +29,17 @@ import ( func RestlikeRequest(_ js.Value, args []js.Value) interface{} { cmixId := args[0].Int() connectionID := args[1].Int() - request := CopyBytesToGo(args[2]) - e2eParamsJSON := CopyBytesToGo(args[3]) + request := utils.CopyBytesToGo(args[2]) + e2eParamsJSON := utils.CopyBytesToGo(args[3]) msg, err := bindings.RestlikeRequest( cmixId, connectionID, request, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(msg) + return utils.CopyBytesToJS(msg) } // RestlikeRequestAuth performs an authenticated restlike request. @@ -55,15 +56,15 @@ func RestlikeRequest(_ js.Value, args []js.Value) interface{} { func RestlikeRequestAuth(_ js.Value, args []js.Value) interface{} { cmixId := args[0].Int() authConnectionID := args[1].Int() - request := CopyBytesToGo(args[2]) - e2eParamsJSON := CopyBytesToGo(args[3]) + request := utils.CopyBytesToGo(args[2]) + e2eParamsJSON := utils.CopyBytesToGo(args[3]) msg, err := bindings.RestlikeRequestAuth( cmixId, authConnectionID, request, e2eParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(msg) + return utils.CopyBytesToJS(msg) } diff --git a/wasm/restlikeSingle.go b/wasm/restlikeSingle.go index a3c546fd1ccf361d6534ed66e885d8cbdbccb476..bcc5e93a74d67028b0489a2e5148d1c0323b307f 100644 --- a/wasm/restlikeSingle.go +++ b/wasm/restlikeSingle.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -21,7 +22,7 @@ type restlikeCallback struct { } func (rlc *restlikeCallback) Callback(payload []byte, err error) { - rlc.callback(CopyBytesToJS(payload), err.Error()) + rlc.callback(utils.CopyBytesToJS(payload), err.Error()) } // RequestRestLike sends a restlike request to a given contact. @@ -37,17 +38,17 @@ func (rlc *restlikeCallback) Callback(payload []byte, err error) { // - Throws a TypeError if parsing the parameters or making the request fails. func RequestRestLike(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - recipient := CopyBytesToGo(args[1]) - request := CopyBytesToGo(args[2]) - paramsJSON := CopyBytesToGo(args[3]) + recipient := utils.CopyBytesToGo(args[1]) + request := utils.CopyBytesToGo(args[2]) + paramsJSON := utils.CopyBytesToGo(args[3]) msg, err := bindings.RequestRestLike(e2eID, recipient, request, paramsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(msg) + return utils.CopyBytesToJS(msg) } // AsyncRequestRestLike sends an asynchronous restlike request to a given @@ -68,15 +69,15 @@ func RequestRestLike(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if parsing the parameters or making the request fails. func AsyncRequestRestLike(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - recipient := CopyBytesToGo(args[1]) - request := CopyBytesToGo(args[2]) - paramsJSON := CopyBytesToGo(args[3]) - cb := &restlikeCallback{WrapCB(args[4], "Callback")} + recipient := utils.CopyBytesToGo(args[1]) + request := utils.CopyBytesToGo(args[2]) + paramsJSON := utils.CopyBytesToGo(args[3]) + cb := &restlikeCallback{utils.WrapCB(args[4], "Callback")} err := bindings.AsyncRequestRestLike( e2eID, recipient, request, paramsJSON, cb) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } diff --git a/wasm/secrets.go b/wasm/secrets.go index f604141e1b9fbdb8052b600ac2b034a51f4039e8..5a7b7127af4cfa5d5292f941553580fc672c086c 100644 --- a/wasm/secrets.go +++ b/wasm/secrets.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -25,5 +26,5 @@ import ( // - secret password (Uint8Array). func GenerateSecret(_ js.Value, args []js.Value) interface{} { secret := bindings.GenerateSecret(args[0].Int()) - return CopyBytesToJS(secret) + return utils.CopyBytesToJS(secret) } diff --git a/wasm/single.go b/wasm/single.go index 3f40bf613bf15ba4fc63d328136a64897a0c66be..7a55ffa7a876b5ab60b42d683ce7e852357f5cc3 100644 --- a/wasm/single.go +++ b/wasm/single.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -36,20 +37,20 @@ import ( // - Throws a TypeError if transmission fails. func TransmitSingleUse(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - recipient := CopyBytesToGo(args[1]) + recipient := utils.CopyBytesToGo(args[1]) tag := args[2].String() - payload := CopyBytesToGo(args[3]) - paramsJSON := CopyBytesToGo(args[4]) - responseCB := &singleUseResponse{WrapCB(args[5], "Callback")} + payload := utils.CopyBytesToGo(args[3]) + paramsJSON := utils.CopyBytesToGo(args[4]) + responseCB := &singleUseResponse{utils.WrapCB(args[5], "Callback")} report, err := bindings.TransmitSingleUse( e2eID, recipient, tag, payload, paramsJSON, responseCB) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } // Listen starts a single-use listener on a given tag using the passed in E2e @@ -67,10 +68,10 @@ func TransmitSingleUse(_ js.Value, args []js.Value) interface{} { // function used to stop the listener. // - Throws a TypeError if listening fails. func Listen(_ js.Value, args []js.Value) interface{} { - cb := &singleUseCallback{WrapCB(args[2], "Callback")} + cb := &singleUseCallback{utils.WrapCB(args[2], "Callback")} api, err := bindings.Listen(args[0].Int(), args[1].String(), cb) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -114,7 +115,7 @@ type singleUseCallback struct { } func (suc *singleUseCallback) Callback(callbackReport []byte, err error) { - suc.callback(CopyBytesToJS(callbackReport), err.Error()) + suc.callback(utils.CopyBytesToJS(callbackReport), err.Error()) } // singleUseResponse wraps Javascript callbacks to adhere to the @@ -124,5 +125,5 @@ type singleUseResponse struct { } func (sur *singleUseResponse) Callback(responseReport []byte, err error) { - sur.callback(CopyBytesToJS(responseReport), err.Error()) + sur.callback(utils.CopyBytesToJS(responseReport), err.Error()) } diff --git a/wasm/ud.go b/wasm/ud.go index 17627eeb6a4bcf5af32fea34d1d51dd973caf648..1c0198a753bfe5c0c2f11ccdd0ef3f06f6cd9618 100644 --- a/wasm/ud.go +++ b/wasm/ud.go @@ -11,6 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" + "gitlab.com/elixxir/xxdk-wasm/utils" "syscall/js" ) @@ -97,17 +98,17 @@ func (uns *udNetworkStatus) UdNetworkStatus() int { // - Throws a TypeError if creating or loading fails. func NewOrLoadUd(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - follower := &udNetworkStatus{WrapCB(args[1], "UdNetworkStatus")} + follower := &udNetworkStatus{utils.WrapCB(args[1], "UdNetworkStatus")} username := args[2].String() - registrationValidationSignature := CopyBytesToGo(args[3]) - cert := CopyBytesToGo(args[4]) - contactFile := CopyBytesToGo(args[5]) + registrationValidationSignature := utils.CopyBytesToGo(args[3]) + cert := utils.CopyBytesToGo(args[4]) + contactFile := utils.CopyBytesToGo(args[5]) address := args[6].String() api, err := bindings.NewOrLoadUd(e2eID, follower, username, registrationValidationSignature, cert, contactFile, address) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -149,18 +150,18 @@ func NewOrLoadUd(_ js.Value, args []js.Value) interface{} { // - Throws a TypeError if getting UD from backup fails. func NewUdManagerFromBackup(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - follower := &udNetworkStatus{WrapCB(args[1], "UdNetworkStatus")} - usernameFactJson := CopyBytesToGo(args[2]) - emailFactJson := CopyBytesToGo(args[3]) - phoneFactJson := CopyBytesToGo(args[4]) - cert := CopyBytesToGo(args[5]) - contactFile := CopyBytesToGo(args[6]) + follower := &udNetworkStatus{utils.WrapCB(args[1], "UdNetworkStatus")} + usernameFactJson := utils.CopyBytesToGo(args[2]) + emailFactJson := utils.CopyBytesToGo(args[3]) + phoneFactJson := utils.CopyBytesToGo(args[4]) + cert := utils.CopyBytesToGo(args[5]) + contactFile := utils.CopyBytesToGo(args[6]) address := args[7].String() api, err := bindings.NewUdManagerFromBackup(e2eID, follower, usernameFactJson, emailFactJson, phoneFactJson, cert, contactFile, address) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -173,7 +174,7 @@ func NewUdManagerFromBackup(_ js.Value, args []js.Value) interface{} { // Returns: // - JSON of [fact.FactList] (Uint8Array). func (ud *UserDiscovery) GetFacts(js.Value, []js.Value) interface{} { - return CopyBytesToJS(ud.api.GetFacts()) + return utils.CopyBytesToJS(ud.api.GetFacts()) } // GetContact returns the marshalled bytes of the [contact.Contact] for UD as @@ -185,11 +186,11 @@ func (ud *UserDiscovery) GetFacts(js.Value, []js.Value) interface{} { func (ud *UserDiscovery) GetContact(js.Value, []js.Value) interface{} { c, err := ud.api.GetContact() if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(c) + return utils.CopyBytesToJS(c) } // ConfirmFact confirms a fact first registered via SendRegisterFact. The @@ -205,7 +206,7 @@ func (ud *UserDiscovery) GetContact(js.Value, []js.Value) interface{} { func (ud *UserDiscovery) ConfirmFact(_ js.Value, args []js.Value) interface{} { err := ud.api.ConfirmFact(args[0].String(), args[1].String()) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -228,9 +229,9 @@ func (ud *UserDiscovery) ConfirmFact(_ js.Value, args []js.Value) interface{} { // - The confirmation ID (string). // - Throws TypeError if sending the fact fails. func (ud *UserDiscovery) SendRegisterFact(_ js.Value, args []js.Value) interface{} { - confirmationID, err := ud.api.SendRegisterFact(CopyBytesToGo(args[0])) + confirmationID, err := ud.api.SendRegisterFact(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -247,9 +248,9 @@ func (ud *UserDiscovery) SendRegisterFact(_ js.Value, args []js.Value) interface // Returns: // - Throws TypeError if deletion fails. func (ud *UserDiscovery) PermanentDeleteAccount(_ js.Value, args []js.Value) interface{} { - err := ud.api.PermanentDeleteAccount(CopyBytesToGo(args[0])) + err := ud.api.PermanentDeleteAccount(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -265,9 +266,9 @@ func (ud *UserDiscovery) PermanentDeleteAccount(_ js.Value, args []js.Value) int // Returns: // - Throws TypeError if removing the fact fails. func (ud *UserDiscovery) RemoveFact(_ js.Value, args []js.Value) interface{} { - err := ud.api.RemoveFact(CopyBytesToGo(args[0])) + err := ud.api.RemoveFact(utils.CopyBytesToGo(args[0])) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } @@ -285,7 +286,7 @@ type udLookupCallback struct { } func (ulc *udLookupCallback) Callback(contactBytes []byte, err error) { - ulc.callback(CopyBytesToJS(contactBytes), err.Error()) + ulc.callback(utils.CopyBytesToJS(contactBytes), err.Error()) } // LookupUD returns the public key of the passed ID as known by the user @@ -305,19 +306,19 @@ func (ulc *udLookupCallback) Callback(contactBytes []byte, err error) { // - Throws a TypeError if the lookup fails. func LookupUD(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - udContact := CopyBytesToGo(args[1]) - cb := &udLookupCallback{WrapCB(args[2], "Callback")} - lookupId := CopyBytesToGo(args[3]) - singleRequestParamsJSON := CopyBytesToGo(args[4]) + udContact := utils.CopyBytesToGo(args[1]) + cb := &udLookupCallback{utils.WrapCB(args[2], "Callback")} + lookupId := utils.CopyBytesToGo(args[3]) + singleRequestParamsJSON := utils.CopyBytesToGo(args[4]) report, err := bindings.LookupUD( e2eID, udContact, cb, lookupId, singleRequestParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) } //////////////////////////////////////////////////////////////////////////////// @@ -331,7 +332,7 @@ type udSearchCallback struct { } func (usc *udSearchCallback) Callback(contactListJSON []byte, err error) { - usc.callback(CopyBytesToJS(contactListJSON), err.Error()) + usc.callback(utils.CopyBytesToJS(contactListJSON), err.Error()) } // SearchUD searches user discovery for the passed Facts. The searchCallback @@ -352,17 +353,17 @@ func (usc *udSearchCallback) Callback(contactListJSON []byte, err error) { // - Throws a TypeError if the search fails. func SearchUD(_ js.Value, args []js.Value) interface{} { e2eID := args[0].Int() - udContact := CopyBytesToGo(args[1]) - cb := &udSearchCallback{WrapCB(args[2], "Callback")} - factListJSON := CopyBytesToGo(args[3]) - singleRequestParamsJSON := CopyBytesToGo(args[4]) + udContact := utils.CopyBytesToGo(args[1]) + cb := &udSearchCallback{utils.WrapCB(args[2], "Callback")} + factListJSON := utils.CopyBytesToGo(args[3]) + singleRequestParamsJSON := utils.CopyBytesToGo(args[4]) report, err := bindings.SearchUD( e2eID, udContact, cb, factListJSON, singleRequestParamsJSON) if err != nil { - Throw(TypeError, err) + utils.Throw(utils.TypeError, err) return nil } - return CopyBytesToJS(report) + return utils.CopyBytesToJS(report) }