用戶端程式庫在 Java 8 (Netty) 和 Android 上提供 WAMP,以及適用於 Android 的(安全)WebSocket。
Autobahn|Java 是 Autobahn 專案的子項目,提供開源客戶端實現
運行在 Android 和 Netty/Java8/JVM 上。
WebSocket 層使用基於回呼的使用者 API,並且是專門為 Android 編寫的。例如,它不在主(UI)執行緒上運行任何網路內容。
WAMP 層使用 Java 8 CompletableFuture進行 WAMP 操作(呼叫、註冊、發布和訂閱),並使用觀察者模式進行 WAMP 會話、訂閱和註冊生命週期事件。
該程式庫獲得 MIT 許可,由 Crossbar.io 專案維護,使用 AutobahnTestsuite 進行測試,並作為 JAR 發佈到 Maven,並作為 Docker 工具鏈映像發佈到 Dockerhub。
透過 Maven 抓取:
< dependency >
< groupId >io.crossbar.autobahn</ groupId >
< artifactId >autobahn-android</ artifactId >
< version >21.7.1</ version >
</ dependency >
搖籃:
dependencies {
implementation ' io.crossbar.autobahn:autobahn-android:21.7.1 '
}
對於非 Android 系統,請使用artifactID autobahn-java
或直接下載最新的 JAR
演示客戶端很容易運行,您只需要安裝make
和docker
即可開始運行。
$ make crossbar # Starts crossbar in a docker container
$ make python # Starts a python based WAMP components that provides calls for the Java demo client
最後
$ make java # Starts the java (Netty) based demo client that performs WAMP actions
demo-gallery 中的程式碼包含一些有關如何使用 autobahn 函式庫的範例,也包含使用的便捷方法。下面是一組基本的程式碼範例,顯示了所有 4 個 WAMP 操作。
public void demonstrateSubscribe ( Session session , SessionDetails details ) {
// Subscribe to topic to receive its events.
CompletableFuture < Subscription > subFuture = session . subscribe ( "com.myapp.hello" ,
this :: onEvent );
subFuture . whenComplete (( subscription , throwable ) -> {
if ( throwable == null ) {
// We have successfully subscribed.
System . out . println ( "Subscribed to topic " + subscription . topic );
} else {
// Something went bad.
throwable . printStackTrace ();
}
});
}
private void onEvent ( List < Object > args , Map < String , Object > kwargs , EventDetails details ) {
System . out . println ( String . format ( "Got event: %s" , args . get ( 0 )));
}
由於我們僅存取 onEvent() 中的args
,因此我們可以將其簡化為:
private void onEvent ( List < Object > args ) {
System . out . println ( String . format ( "Got event: %s" , args . get ( 0 )));
}
public void demonstratePublish ( Session session , SessionDetails details ) {
// Publish to a topic that takes a single arguments
List < Object > args = Arrays . asList ( "Hello World!" , 900 , "UNIQUE" );
CompletableFuture < Publication > pubFuture = session . publish ( "com.myapp.hello" , args );
pubFuture . thenAccept ( publication -> System . out . println ( "Published successfully" ));
// Shows we can separate out exception handling
pubFuture . exceptionally ( throwable -> {
throwable . printStackTrace ();
return null ;
});
}
一個更簡單的呼叫如下所示:
public void demonstratePublish ( Session session , SessionDetails details ) {
CompletableFuture < Publication > pubFuture = session . publish ( "com.myapp.hello" , "Hi!" );
...
}
public void demonstrateRegister ( Session session , SessionDetails details ) {
// Register a procedure.
CompletableFuture < Registration > regFuture = session . register ( "com.myapp.add2" , this :: add2 );
regFuture . thenAccept ( registration ->
System . out . println ( "Successfully registered procedure: " + registration . procedure ));
}
private CompletableFuture < InvocationResult > add2 (
List < Object > args , Map < String , Object > kwargs , InvocationDetails details ) {
int res = ( int ) args . get ( 0 ) + ( int ) args . get ( 1 );
List < Object > arr = new ArrayList <>();
arr . add ( res );
return CompletableFuture . completedFuture ( new InvocationResult ( arr ));
}
一個非常精確的add2
可能看起來像:
private List < Object > add2 ( List < Integer > args , InvocationDetails details ) {
int res = args . get ( 0 ) + args . get ( 1 );
return Arrays . asList ( res , details . session . getID (), "Java" );
}
public void demonstrateCall ( Session session , SessionDetails details ) {
// Call a remote procedure.
CompletableFuture < CallResult > callFuture = session . call ( "com.myapp.add2" , 10 , 20 );
callFuture . thenAccept ( callResult ->
System . out . println ( String . format ( "Call result: %s" , callResult . results . get ( 0 ))));
}
使用可變資料類型參數呼叫過程
public void demonstrateCall ( Session session , SessionDetails details ) {
// Call a remote procedure.
byte [] var1 = new byte [ 20 ];
String var2 = "A sample text" ;
int var3 = 99 ;
List < Object > args = new ArrayList <>();
args . add ( var1 );
args . add ( var2 );
args . add ( var3 );
CompletableFuture < CallResult > callFuture = session . call ( "com.myapp.myproc" , args );
callFuture . thenAccept ( callResult ->
System . out . println ( String . format ( "Call result: %s" , callResult . results . get ( 0 ))));
}
public void main () {
// Create a session object
Session session = new Session ();
// Add all onJoin listeners
session . addOnJoinListener ( this :: demonstrateSubscribe );
session . addOnJoinListener ( this :: demonstratePublish );
session . addOnJoinListener ( this :: demonstrateCall );
session . addOnJoinListener ( this :: demonstrateRegister );
// finally, provide everything to a Client and connect
Client client = new Client ( session , url , realm );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
身份驗證很簡單,我們只需建立所需身份驗證器的物件並將其傳遞給客戶端
public void main () {
...
IAuthenticator authenticator = new TicketAuth ( authid , ticket );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
public void main () {
...
IAuthenticator authenticator = new ChallengeResponseAuth ( authid , secret );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
public void main () {
...
IAuthenticator authenticator = new CryptosignAuth ( authid , privkey , pubkey );
Client client = new Client ( session , url , realm , authenticator );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
您也可以提供身份驗證器列表
public void main () {
...
List < IAuthenticator > authenticators = new ArrayList <>();
authenticators . add ( new TicketAuth ( authid , ticket ));
authenticators . add ( new CryptosignAuth ( authid , privkey , pubkey ));
Client client = new Client ( session , url , realm , authenticators );
CompletableFuture < ExitInfo > exitInfoCompletableFuture = client . connect ();
}
Autobahn 也支援 POJO
以下是如何呼叫傳回 Person POJO 清單的遠端過程
// Call a remote procedure that returns a Person with id 1
CompletableFuture < Person > callFuture = mSession . call ( "com.example.get_person" , 1 );
callFuture . whenCompleteAsync (( person , throwable ) -> {
if ( throwable != null ) {
// handle error
} else {
// success!
// do something with person
}
}, mExecutor );
// call a remote procedure that returns a List<Person>
CompletableFuture < List < Person >> callFuture = mSession . call (
// remote procedure to call
"com.example.get_persons_by_department" ,
// positional call arguments
new ArrayList < Object >() { List . of ( "department-7" )},
// call return type
new TypeReference < List < Person >>() {}
);
callFuture . whenCompleteAsync (( persons , throwable ) -> {
if ( throwable != null ) {
// handle error
} else {
// success!
for ( Person person : persons ) {
// do something with person
}
}
}, mExecutor );
也註冊一個返回 Person 的過程
private Person get_person () {
return new Person ( "john" , "doe" , "hr" );
}
private void main () {
CompletableFuture < Registration > regFuture = session . register (
"io.crossbar.example.get_person" , this :: get_person );
regFuture . whenComplete (( registration , throwable ) -> {
System . out . println ( String . format (
"Registered procedure %s" , registration . procedure ));
});
}
迴聲範例
WebSocketConnection connection = new WebSocketConnection ();
connection . connect ( "wss://echo.websocket.org" , new WebSocketConnectionHandler () {
@ Override
public void onConnect ( ConnectionResponse response ) {
System . out . println ( "Connected to server" );
}
@ Override
public void onOpen () {
connection . sendMessage ( "Echo with Autobahn" );
}
@ Override
public void onClose ( int code , String reason ) {
System . out . println ( "Connection closed" );
}
@ Override
public void onMessage ( String payload ) {
System . out . println ( "Received message: " + payload );
connection . sendMessage ( payload );
}
});
建造高速公路非常簡單
對於 Android,我們建議使用 Android Studio。只需在 Android Studio 中匯入項目,它會告訴您是否缺少任何依賴項,安裝它們,然後只需從Build > Rebuild Project
建置項目,您將在autobahn/build/outputs/aar/
中獲得 aar 工件
要為非 Android 系統生成構建,請確保安裝了 docker 並 make,然後只需在專案的根目錄下使用運行以下命令
make build_autobahn
這將在autobahn/build/libs/
中輸出 jar 檔案。
透過加入我們的論壇來取得聯繫。
該庫的版本 1 仍在此處的儲存庫中,但不再維護。
版本 1 僅支援 Android 上的非安全性 WebSocket,並且僅支援 WAMP v1。
這兩個問題都已在 Autobahn|Java 的(目前)版本中修復。