WebCFace 2.5.2
Web-based Communication Framework & Dashboard-like UI
Loading...
Searching...
No Matches
5-3. Func

Since
See also

他Memberから呼び出せる関数の登録、 また他Memberの関数の呼び出しができます。

関数の登録

  • C++ Client::func からFuncオブジェクトを作り、 Func::set() で関数を登録し、Client::sync()することで送信されます

    関数は関数オブジェクト(ラムダ式など)でもokです。 引数、戻り値は整数、実数、bool、文字列型であれば自由に指定できます。

    void hoge() {
    std::cout << "hello, world!" << std::endl;
    }
    double fuga(int a, const std::string &b) {
    return 3.1415;
    }
    wcli.func("hoge").set(hoge);
    wcli.func("fuga").set(fuga);
    // or, using lambda:
    wcli.func("hoge").set([](){ /* ... */ });
    wcli.func("fuga").set([](int a, const std::string &b){ return 3.1415; });
    • set() の代わりに代入演算子(Func::operator=)でも同様のことができます
      • 2.0 代入演算子はdeprecatedになりました
    • 同じ名前のFuncに複数回関数をセットすると上書きされ、後に登録した関数のみが呼び出されます。 ただし引数や戻り値の型などの情報は更新されず、最初の関数のものと同じになります。
    • 関数の中で例外をthrowした場合WebCFace側でcatchされ、エラーメッセージが呼び出し元に返ります。
    • 2.0 set()で登録した関数はClient::sync()時に同じスレッドで実行されます。 そのため長時間かかる関数を登録するとその間他の処理がブロックされることになります。
      • 関数を非同期(別スレッド)で実行したい場合は Func::setAsync() を使用してください。 ver1.11以前ではset()で登録した関数はすべて非同期実行されていたので、こちらが従来のset()と同じ挙動になります。
      • ただしその場合排他制御が必要なら登録する関数内で適切に行ってください
        wcli.func("hoge").setAsync([](){
        std::this_thread::sleep_for(std::chrono::seconds(5));
        return "hello";
        });
    Warning
    2.0 set()で登録した関数はClient::sync() の中で呼び出されるため、
    • sync() が呼び出される頻度が少ない場合、呼び出されてから実際に関数を実行するまでにラグが生じます。 その場合はsync()を呼び出す頻度を上げるか、loopSync() を使ってください (4-1. Client 参照)
    • set()で登録した関数内で他のクライアントの関数をrun()やrunAsync()で呼び出して結果を受け取ろうとするとデッドロックしてしまいます。 (結果を受け取る処理も sync() で行われるため)
      wcli.func("hoge").set([&](){
      wcli.member("foo").func("piyo").runAsync().waitFinish(); // deadlock
      std::async([&]{
      wcli.member("foo").func("piyo").waitFinish(); // ok (非同期実行)
      });
      // またはそもそもこの関数をsetAsync()で登録すればok
      });

  • JavaScript Client.func からFuncオブジェクトを作り、 Func.set() で関数を登録し、Client.sync()することで送信されます

    引数、戻り値はnumber, bool, string型であればいくつでも自由に指定できます。

    wcli.func("hoge").set(() => {/* ... */});
    wcli.func("hoge").set((a: number, b: string) => 3.1415);
    • 関数の中で例外をthrowした場合WebCFace側でcatchされ、エラーメッセージが呼び出し元に返ります。
    • 同じ名前のFuncに複数回関数をセットすると上書きされ、後に登録した関数のみが呼び出されます。 ただし引数や戻り値の型などの情報は更新されず、最初の関数のものと同じになります。
  • Python Client.func からFuncオブジェクトを作り、 Func.set() で関数を登録し、Client.sync()することで送信されます

    def hoge(a, b):
    return 3.1415
    wcli.func("hoge").set(hoge)
    wcli.func("lambda").set(lambda x: return x + 5) # ラムダ式なども可
    • 関数の中で例外をraiseした場合WebCFace側でcatchされ、エラーメッセージが呼び出し元に返ります。
    • 同じ名前のFuncに複数回関数をセットすると上書きされ、後に登録した関数のみが呼び出されます。 ただし引数や戻り値の型などの情報は更新されず、最初の関数のものと同じになります。
    • setを明示的に呼び出す代わりにfuncオブジェクトをデコレータにすると簡単に登録できます。
      @wcli.func("hoge")
      def hoge(a, b):
      return 3.1415
    • デコレータとして使用する場合func()の引数に関数名を書くのを省略すると実際の関数の名前が自動で取得され設定されます。
      • () は必須です。(@wcli.func をデコレータとして使わないでください。)
        @wcli.func()
        def hoge(a, b):
        return 3.1415
    • 2.0 set() で登録した関数はClient.sync()時に同じスレッドで実行されます。 そのため長時間かかる関数を登録するとその間他の処理がブロックされることになります。
      • 関数を非同期(別スレッド)で実行したい場合は Func.set_async() を使用してください。 ver1.11以前ではset()で登録した関数はすべて非同期実行されていたので、こちらが従来のset()と同じ挙動になります。
      • set_async() で登録した関数は新しいスレッド(threading.Thread)で実行されます。
        def hoge(a, b):
        time.sleep(5)
        wcli.func("hoge").set_async(hoge)
    Warning
    2.0 set()で登録した関数はClient.sync() の中で呼び出されるため、
    • sync() が呼び出される頻度が少ない場合、呼び出されてから実際に関数を実行するまでにラグが生じます。 その場合はsync()を呼び出す頻度を上げるか、sync(timeout) を使ってください (4-1. Client 参照)
    • set()で登録した関数内で他のクライアントの関数をrun()やrun_async()で呼び出して結果を受け取ろうとするとデッドロックしてしまいます。 (結果を受け取る処理も sync() で行われるため)
      @wcli.func()
      def hoge():
      wcli.member("foo").func("piyo").run() # deadlock
      def wait_piyo():
      wcli.member("foo").func("piyo").run() # ok (非同期実行)
      threading.Thread(target=wait_piyo)
      # またはそもそもこの関数をsetAsync()で登録すればok

setした関数にWebCFace側で排他制御をかける機能(〜ver1.11まで)

C++では呼び出された関数は別スレッドで非同期に実行されます。 これをメインスレッドと同期させたい場合は実行条件を設定することができます。

wcli.func("fuga").setRunCondOnSync();

とすると呼び出された関数の実行は wcli.sync() のときに行われます。

struct ScopeGuard {
static std::mutex m;
ScopeGuard() { m.lock(); }
~ScopeGuard() { m.unlock(); }
};
wcli.func("fuga").setRunCondScopeGuard<ScopeGuard>();

とすると任意のScopeGuardクラスを使うことができます (実行前にScopeGuardのコンストラクタ、実行後にデストラクタが呼ばれます)

また、すべての関数にまとめて条件を設定したい場合は、関数の設定前に

wcli.setDefaultRunCondOnSync();
wcli.setDefaultRunCondScopeGuard<ScopeGuard>();

とするとデフォルトの条件を設定できます。

デフォルトを設定した後個別の関数について条件を設定することもできますし、

wcli.func("fuga").setRunCondNone();

で条件を何も課さないようにできます。

CallHandle

  • C++
    Since
    2.4
    引数に webcface::CallHandle をとる関数をセットすることもできます。
    wcli.func("hoge").set([](webcface::CallHandle handle){
    double arg = handle.args().at(0).asDouble();
    handle.respond(123); // return value
    }).setArgs({
    });
    引数の情報を表す。
    Definition arg.h:30
    ValType type() const
    引数の型を取得する。
    Definition func_info.cc:57
    呼び出された関数の引数の取得と戻り値のセットをするインタフェース
    Definition func_result.h:323
    void respond(const ValAdaptor &value) const
    Definition func_result.cc:83
    const std::vector< ValAdaptor > & args() const
    関数の引数を取得する
    Definition func_result.cc:332
    • 通常の関数のset()の場合と同様、関数を非同期(別スレッド)で実行したい場合は setAsync() を使用してください。
    • 関数のsetのあとに、 setArgs() で受け取りたい引数の個数分の webcface::Arg() を渡し、引数名や戻り値の型を指定します。
      • 引数名などの情報が不要な場合でも引数の個数分 Arg() を渡す必要があります。
    • callbackが呼び出されたとき、引数に渡されたhandleを介して handle.args() でFuncを呼び出した引数を取得できます。
      • setArgs() で指定した引数の個数と呼び出し時の個数が一致しない場合は、callbackが実行される前に呼び出し元にエラーメッセージが投げられます。 (そのため登録した関数の側で引数の個数チェックをする必要はないです)
    • 値を返すのはreturnではなくhandleを介して handle.respond(戻り値) を使います。
      • 戻り値が不要な場合はrespondに何も渡さず handle.respond(); とします。
    • エラーメッセージを返すには handle.reject(エラーメッセージ) を使います。
      • 関数の中で例外をthrowした場合もエラーメッセージが呼び出し元に返ります。
    • respondかrejectを呼び出すまで、Funcの呼び出し元には関数呼び出しの結果は送られません。
      • そのためhandleを関数の外のスコープの変数に保存(コピー)したり、別スレッドに持ち込むことで任意のタイミングで結果を返すことも可能です。
  • C

    Since
    1.9

    wcfFuncSet, (2.0 wcfFuncSetW) で関数ポインタを登録できます。
    登録する関数の引数は wcfFuncCallHandle*, (2.0 wcfFuncCallHandleW*) と void* の2つで、 前者は引数のデータを取得したり結果を返すのに使用します。 後者には登録時に任意のデータのポインタを渡すことができます。(使用しない場合はNULLでよいです。)

    void callback(wcfFuncCallHandle *handle, void *user_data_p) {
    struct UserData *user_data = (struct UserData *)user_data_p;
    // do something
    wcfMultiVal ans = wcfValI(123); // return value
    wcfFuncRespond(handle, ans);
    }
    struct UserData user_data = {...};
    wcfFuncSet(wcli, "hoge", args_type, 3, WCF_VAL_INT, callback, &user_data);
    wcfStatus wcfFuncRespond(const wcfFuncCallHandle *handle, const wcfMultiVal *value)
    関数呼び出しに対して値を返す
    Definition func.cc:332
    wcfMultiVal wcfValI(int value)
    int型のwcfMultiValを構築
    Definition func.cc:249
    wcfStatus wcfFuncSet(wcfClient *wcli, const char *field, const wcfValType *arg_types, int arg_size, wcfValType return_type, wcfFuncCallback callback, void *user_data)
    関数を登録する
    Definition func.cc:286
    wcfValType
    Definition def_types.h:30
    @ WCF_VAL_STRING
    Definition def_types.h:32
    @ WCF_VAL_DOUBLE
    Definition def_types.h:35
    @ WCF_VAL_INT
    Definition def_types.h:34
    受信した関数呼び出しの情報を保持するstruct
    Definition def_types.h:111
    数値と文字列をまとめて扱うためのstruct
    Definition def_types.h:50
    • set時には受け取りたい引数の型、個数、戻り値の型を指定します。 型は WCF_VAL_NONE, WCF_VAL_STRING, WCF_VAL_BOOL, WCF_VAL_INT, WCF_VAL_DOUBLE が指定できます。
    • 同じ名前のFuncに複数回関数をセットすると上書きされ、後に登録した関数のみが呼び出されます。 ただし引数や戻り値の型などの情報は更新されず、最初の関数のものと同じになります。
    • 2.0 wcfFuncSet(), wcfFuncSetW() で登録した関数はwcfSync()時に同じスレッドで実行されます。 そのため長時間かかる関数を登録するとその間他の処理がブロックされることになります。
      • 関数を非同期(別スレッド)で実行したい場合は wcfFuncSetAsync(), wcfFuncSetAsyncW() を使用してください。 ver1.11以前ではwcfFuncSet()で登録した関数はすべて非同期実行されていたので、こちらが従来のwcfFuncSet()と同じ挙動になります。
      • (ただしその場合排他制御が必要なら登録する関数内で適切に行ってください)
        wcfFuncSetAsync(wcli, "hoge", args_type, 3, WCF_VAL_INT, callback, &user_data);
        wcfStatus wcfFuncSetAsync(wcfClient *wcli, const char *field, const wcfValType *arg_types, int arg_size, wcfValType return_type, wcfFuncCallback callback, void *user_data)
        非同期に実行される関数を登録する
        Definition func.cc:300
    • callbackが呼び出されたとき、引数に渡されたhandleを介して handle->args でFuncを呼び出した引数を取得できます。
      • set時に指定した引数の個数と呼び出し時の個数が一致しない場合は、callbackが実行される前に呼び出し元にエラーメッセージが投げられます。 (そのため引数の個数チェックをする必要はないです)
    • 値を返すのはreturnではなくhandleを介して wcfFuncRespond, (2.0 wcfFuncRespondW) を使います。
      wcfMultiVal ans = wcfValD(123.45);
      wcfFuncRespond(handle, &ans);
      wcfMultiVal wcfValD(double value)
      double型のwcfMultiValを構築
      Definition func.cc:250
    • 戻り値が不要な場合は wcfFuncRespond(handle, NULL); とします。
    • エラーメッセージを返すには wcfFuncReject, (2.0 wcfFuncRejectW) を使います。 (wcfFuncReject(handle, NULL); も可)
      wcfFuncReject(handle, "エラーメッセージ");
      wcfStatus wcfFuncReject(const wcfFuncCallHandle *handle, const char *message)
      関数呼び出しに対してエラーメッセージを返す
      Definition func.cc:340
    • respondもrejectもせずにreturnした場合は自動的に空の値でrespondします。
      • 2.0 respondかrejectを呼び出すまで、Funcの呼び出し元には関数呼び出しの結果は送られません。
      • そのためhandleポインタを関数の外のスコープの変数に保存したり、別スレッドに持ち込むことで任意のタイミングで結果を返すことも可能です。
    Warning
    2.0 wcfFuncSet()で登録した関数はwcfSync() の中で呼び出されるため、
    • wcfSync() が呼び出される頻度が少ない場合、呼び出されてから実際に関数を実行するまでにラグが生じます。 その場合はwcfSync()を呼び出す頻度を上げるか、wcfLoopSync() を使ってください (4-1. Client 参照)
    • wcfFuncSet()で登録した関数内で他のクライアントの関数をwcfFuncRun()やwcfFuncRunAsync()で呼び出して結果を受け取ろうとするとデッドロックしてしまいます。 (結果を受け取る処理も wcfSync() で行われるため) その場合はwcfFuncSetAsync()を使用してください。

  • Python
    Since
    2.2
    引数に webcface.CallHandle をとる関数をセットすることもできます。
    def hoge(handle):
    a = handle.args[0]
    handle.respond(123) # return value
    wcli.func("hoge").set(hoge,
    handle=True,
    return_type=int,
    args=[Arg("a", type=int)]
    )
    • 通常の関数との区別のため、set()の引数に handle=True を渡すか、または引数の型アノテーションで CallHandle を指定するかのどちらかが必要です。
      • デコレータで登録する場合はset()の代わりに func() の引数にhandle=Trueを渡してください。
    • 通常の関数のset()の場合と同様、関数を非同期(別スレッド)で実行したい場合は set_async() を使用してください。
    • 関数のset時に、戻り値の型と、受け取りたい引数の個数分の webcface.Arg を渡し、引数名や型を指定してください。
      • デコレータで登録する場合はset()の代わりに func() の引数に渡してください。
    • callbackが呼び出されたとき、引数に渡されたhandleを介して handle.args でFuncを呼び出した引数を取得できます。
      • set時に指定した引数の個数と呼び出し時の個数が一致しない場合は、callbackが実行される前に呼び出し元にエラーメッセージが投げられます。 (そのため登録した関数の側で引数の個数チェックをする必要はないです)
    • 値を返すのはreturnではなくhandleを介して handle.respond(戻り値) を使います。
      • 戻り値が不要な場合はrespondに何も渡さず handle.respond() とします。
    • エラーメッセージを返すには handle.reject(エラーメッセージ) を使います。
      • 関数の中で例外をthrowした場合もエラーメッセージが呼び出し元に返ります。
    • respondかrejectを呼び出すまで、Funcの呼び出し元には関数呼び出しの結果は送られません。
      • そのためhandleを関数の外のスコープの変数に保存(コピー)したり、別スレッドに持ち込むことで任意のタイミングで結果を返すことも可能です。

引数と戻り値型

  • C++ 引数型や戻り値型は関数の型から自動で取得されますが、 引数名などの情報や引数に設定する条件などを Func::setArgs() でセットすることができます。 設定可能な情報の一覧は webcface::Arg を参照

    関数をsetする前に呼ぶとエラーになります。 また、実際の関数の引数と個数が一致していなければ std::invalid_argument を投げます。

    wcli.func("fuga").setArgs({
    webcface::Arg("a").init(100),
    webcface::Arg("b").option({"aaa", "bbb", "ccc"}),
    });
    std::optional< ValAdaptor > init() const
    デフォルト値を取得する。
    Definition func_info.cc:62
    const std::vector< ValAdaptor > & option() const
    引数の選択肢を取得する。
    Definition func_info.cc:85
  • JavaScript 引数名、引数や戻り値の型、その他の引数に関する情報をset関数の引数で指定します。 引数のオプションに関しては Arg を参照
    wcli.func("hoge").set(
    () => { /*...*/ }, // 関数
    valType.float_, // 戻り値の型
    [ // 引数の情報
    { name: "a", type: valType.int_, init: 100 },
    { name: "b", type: valType.string_, option: ["aaa", "bbb", "ccc"] },
    ],
    );
  • Python Pythonではset()関数の引数にオプションで args と return_type を渡すことで型やその他の情報を指定できます。 argsの引数に関しては webcface.Arg を参照

    引数名については実際の引数名が自動的に取得されます。

    from webcface import Arg
    def hoge(a, b):
    return 3.1415
    wcli.func("hoge").set(hoge, return_type=float, args=[
    Arg(type=int, init=100),
    Arg(type=str, option=["aaa", "bbb", "ccc"]),
    ])

    デコレータで登録する場合はset()の代わりにfunc()の引数に渡してください。

    @wcli.func(return_type=float, args=[
    Arg(type=int, init=100),
    Arg(type=str, option=["aaa", "bbb", "ccc"]),
    ])
    def hoge(a, b):
    return 3.1415

    引数と戻り値の型アノテーションをすると、型の指定を省略できます。 また、デフォルト引数も指定されていればそれが使われます。

    def hoge(a: int = 100, b: str = "aaa") -> float:
    return 3.1415
    wcli.func("hoge").set(hoge, args=[
    Arg(),
    Arg(option=["aaa", "bbb", "ccc"]),
    ])

    2.2 実際の関数の引数とargsで指定した個数が一致していなければAssertionErrorになります。

型変換

  • 関数登録時に指定した型と呼び出したときに渡した引数の型が違う場合、呼び出された側のライブラリが自動的に変換してから関数に渡します。
  • (ver1.5.3〜1.9.0のserverではすべて文字列型に置き換えられてしまうバグあり、ver1.9.1で修正)
  • 変換規則は基本的には呼び出された側の言語仕様の標準に従います。
    • 文字列→数値は10進数で変換されます。小数点以下の桁数や、指数表記にするかどうかは未規定です
    • 数値→文字列も10進数としてパースされます。数値でない文字列が渡された場合の処理は未規定です
  • bool→文字列
    • C++: 0, 1
    • Python: False, True 3.0 0, 1
    • JavaScript: false, true
  • 文字列→bool
    • C++: "1" のみtrue 1.9.1 空文字列でないときtrue
    • Python: 空文字列でないときTrue
    • JavaScript: 空文字列でないときtrue
  • (C++) 引数を webcface::ValAdaptor 型にすると型変換を行わずに値を受け取ることができます。
  • (C) set時に指定した引数の型によらず、callHandleからは常にint,double,文字列のいずれでも値を受け取ることができます。
  • (JavaScript) set時に引数の型の情報を指定しなかった場合、型変換を行わず送られてきた値をそのまま関数に渡します。
  • (Python) 3.0 関数登録時に指定した型が int,float,bool,str のいずれでもないもしくは未指定の場合、 型変換を行わず送られてきた値をそのまま関数に渡します。

関数をWebUIから隠す

(serverが1.10以降の場合)

関数の名前を半角ピリオドから始めると、Entryが他クライアントに送信されなくなり、 他のMemberやWebUIから関数の存在を隠すことができます。 (Valueなど他のデータ型についても同様です。)

なお半角ピリオド2つから始まる名前はwebcface内部の処理で利用する場合があるので使用しないでください。

以前のバージョンでは名前に関係なく関数を非表示にするオプションがありましたが、削除しました。

以前のバージョン

hidden属性をつけると他のMemberやWebUIから関数の存在を隠すことができます。 Client::funcEntries()でその関数の存在を確認したりFunc::args()などでの情報の取得ができなくなります。 ただし関数の名前がわかっていれば他Memberからでも実行は可能です。

  • C++
    func.hidden(true)
    で設定できます。
  • JavaScript 1.0.4 set()関数の4番目の引数にtrueを指定することでできます。
    wcli.func("hoge").set(hoge, valType.float_, [ ... ], true);
  • Python set()関数(デコレータの場合はfunc())の引数に指定することで設定できます。
    wcli.func("hoge").set(hoge, return_type=float, args=[...], hidden=True)

FuncListener

呼び出されたとき実行する関数を登録する代わりに、呼び出されたかどうかを監視し任意のタイミングで値を返すということもできます。 特にCのFFIで関数ポインタが利用できない場合に代わりに使えます。

  • C++

    Since
    1.5
    wcli.funcListener("hoge").listen();

    で待ち受けを開始し、func.set()と同様関数が登録され他クライアントから見られるようになります。 (listen()自体は関数呼び出しを待機することはありません)

    引数を受け取りたい場合は

    wcli.funcListener("hoge").listen(3);

    のように引数の個数を指定するか、または

    wcli.funcListener("hoge").setArgs({...}).listen();

    とすると通常のfuncと同様引数のオプションを設定可能です。 (func.setArgs()はfunc.set()の後でしたが、funcListenerではlisten()の前に実行する必要があります。)

    その後、任意のタイミングで

    std::optional<webcface::CallHandle> handle = wcli.funcListener("hoge").fetchCall();

    とすることで関数が呼び出されたかどうかを調べることができます。

    • その関数がまだ呼び出されていない場合はstd::nulloptが返ります。
    • 関数が呼び出された場合、 CallHandle::args() で呼び出された引数を取得できます。
      • 各引数は ValAdaptor 型で取得でき、 asStringRef(), asString(), asBool(), as<double>(), 2.0 asWStringRef(), asWString(), asDouble(), asInt(), asLLong() で型を指定して取得できます。
      • (std::string, double, bool などの型にキャストすることでも値を得られます。)
      • listen時に指定した引数の個数と呼び出し時の個数が一致しない場合、fetchCallで取得する前に呼び出し元に例外が投げられます (そのため引数の個数チェックをする必要はないです)
    • 通常の関数のreturnの代わりに、handle.respond() で関数呼び出しの終了を表し、戻り値を返すことができます。
    • またthrowの代わりに handle.reject() でエラーメッセージを返すことができます。

    詳細は webcface::CallHandle (ver2.0で FuncCallHandle から CallHandle に名前変更)

  • C

    wcfFuncListen(wcli, "hoge", args_type, 3, WCF_VAL_INT);
    wcfStatus wcfFuncListen(wcfClient *wcli, const char *field, const wcfValType *arg_types, int arg_size, wcfValType return_type)
    関数呼び出しの待受を開始する
    Definition func.cc:314

    で待ち受けを開始し、wcfFuncSet() と同様関数が登録され他クライアントから見られるようになります。 (wcfFuncListen()自体は関数呼び出しを待機することはありません)

    その後、任意のタイミングで

    wcfFuncFetchCall(wcli, "hoge", &handle);
    wcfStatus wcfFuncFetchCall(wcfClient *wcli, const char *field, wcfFuncCallHandle **handle)
    関数が呼び出されたかどうかを確認
    Definition func.cc:324

    とすることで関数が呼び出されたかどうかを調べることができます。

    • その関数がまだ呼び出されていない場合はWCF_NOT_CALLEDが返ります。
    • 関数が呼び出された場合WCF_OKが返り、handle->argsに引数が格納されます。
      • listen時に指定した引数の個数と呼び出し時の個数が一致しない場合、fetchCallで取得する前に呼び出し元に例外が投げられます (そのため引数の個数チェックをする必要はないです)
    • 通常の関数のreturnの代わりに、 wcfFuncRespond, (2.0 wcfFuncRespondW) で関数呼び出しの終了を表し、戻り値を返すことができます。
      wcfMultiVal ans = wcfValD(123.45);
      wcfFuncRespond(handle, &ans);
    • 1.9 戻り値が不要な場合は wcfFuncRespond(handle, NULL); とします。
    • または wcfFuncReject, (2.0 wcfFuncRejectW) でエラーメッセージを返すことができます。 (wcfFuncReject(handle, NULL); も可)
      wcfFuncReject(handle, "エラーメッセージ");
  • Python

    Since
    2.2
    wcli.funcListener("hoge").listen()

    で待ち受けを開始し、func.set()と同様関数が登録され他クライアントから見られるようになります。 (listen()自体は関数呼び出しを待機することはありません)

    引数を受け取りたい場合は

    wcli.funcListener("hoge").listen(args=[...])

    のように引数の個数分の Arg を指定してください。

    その後、任意のタイミングで

    handle = wcli.funcListener("hoge").fetch_call()

    とすることで関数が呼び出されたかどうかを調べることができます。

    • その関数がまだ呼び出されていない場合はNoneが返ります。
    • 関数が呼び出された場合、 handle.args で呼び出された引数を取得できます。
      • listen時に指定した引数の個数と呼び出し時の個数が一致しない場合、fetch_callで取得する前に呼び出し元に例外が投げられます (そのため引数の個数チェックをする必要はないです)
    • 通常の関数のreturnの代わりに、handle.respond() で関数呼び出しの終了を表し、戻り値を返すことができます。
    • またthrowの代わりに handle.reject() でエラーメッセージを返すことができます。

    詳細は webcface.CallHandle

関数の情報の取得

関数の引数や戻り値の情報を取得できます。 他のデータ型と違ってデータをリクエストする機能はなく、 関数の情報はクライアントが関数を登録してsync()した時点で送られてきます。

  • C++ Member::func() でFuncクラスのオブジェクトが得られ、 Func::returnType() や Func::args() で関数の引数や戻り値の情報を取得できます。
    std::vector<webcface::Arg> args = wcli.member("foo").func("hoge").args();
    webcface::ValType return_type = wcli.member("foo").func("hoge").returnType();
    ValType
    引数や戻り値の型を表すenum
    Definition val_adaptor.h:21
    引数の情報については webcface::Arg を参照 また、戻り値型は webcface::ValType というenum型で得られます。
  • JavaScript Member.func() でFuncクラスのオブジェクトが得られ、 Func.returnType や Func.args で関数の引数や戻り値の情報を取得できます。
    const args = wcli.member("foo").func("hoge").args;
    const returnType = wcli.member("foo").func("hoge").returnType;
    引数の情報については Arg を参照
  • Python Member.func() でFuncクラスのオブジェクトが得られ、 Func.return_type や Func.args で関数の引数や戻り値の情報を取得できます。
    args = wcli.member("foo").func("hoge").args
    return_type = wcli.member("foo").func("hoge").return_type
    引数の情報については webcface.Arg を参照

Entry

Valueと同様、関数が存在するかどうかを取得することができます。 使い方は Value と同様なのでそちらを参照してください

関数の実行

他クライアントに登録された関数を呼び出すことができます。 (自分でsetした関数を自分で実行することも一応可能です)

引数を渡したり、戻り値またはエラーメッセージを取得することができます。

  • C++ Func::runAsync() で関数を呼び出し、完了を待たずに続行します。 戻り値として AsyncFuncResult 2.0 Promise クラスのオブジェクトが返り、後から関数の戻り値や例外を取得できます。

    2.0 Promiseでは以下のメソッドが使用可能です。

    • reached(): 関数呼び出しのメッセージが相手のクライアントに到達したらtrue、それまでの間はfalseです。
      • waitReach(), waitReachFor(), waitReachUntil(): reached()がtrueになるまで待機します。 For, Until の場合はタイムアウトを指定します。
    • found(): reached()がtrueになった後、相手のクライアントが関数の実行を開始したらtrue、指定したクライアントまたは関数が存在しなかった場合falseです。
      • reached()がfalseの間はfalseです。
      • runAsync呼び出し時にクライアントがサーバーに接続していなかった場合は、関数呼び出しメッセージを送信することなく即座にfalseになります
    • finished(): 関数の実行が完了し戻り値かエラーメッセージを受け取ったらtrue、それまでの間はfalseです。
      • waitFinish(), waitFinishFor(), waitFinishUntil(): finished()がtrueになるまで待機します。 For, Until の場合はタイムアウトを指定します。
    • response(): 関数の戻り値です。 webcface::ValAdaptor 型で返り、 asStringRef(), asString(), asWStringRef(), asWString(), asBool(), asDouble(), asInt(), asLLong() またはstatic_castにより型変換できます。
    • rejection(), rejectionW(): 関数が例外を返した場合そのエラーメッセージを表す文字列です。 またその場合 isError() がtrueになります。
    Promise res = wcli.member("foo").func("hoge").runAsync(1, "aa");
    res.waitReach();
    if(res.found()){
    // 関数hogeが存在し、実行が開始された
    res.waitFinish();
    if(res.isError()){
    // res.rejection() がエラーメッセージ
    }else{
    // res.response() が戻り値
    }
    }else{
    // 関数hogeが存在しないか未接続で呼び出し失敗
    }
    Warning
    2.0 上の例のようにwaitReach(), waitFinish() などで結果が返ってくるまで待機することができますが、 これらが結果を受信するためには Client::sync() が必要なため、別スレッドでsync()が呼ばれていなければデッドロックします。

    • onReach(), onFinish() で値が返ってきたときに実行されるコールバックを設定することができます。
      • 引数にはそのPromise自身が渡されますが、(キャプチャするなどして)必要なければ引数なしの関数も設定可能です
      • コールバックは Client::sync() の中から呼び出されます。
        Promise res = wcli.member("foo").func("hoge").runAsync(1, "aa");
        res.onReach([](Promise res){
        if(res.found()){
        // 関数hogeが存在し、実行が開始された
        }else{
        // 関数hogeが存在しないか未接続で呼び出し失敗
        }
        });
        res.onFinish([](Promise res){
        if(res.isError()){
        // res.rejection() がエラーメッセージ
        }else{
        // res.response() が戻り値
        }
        });
    Note
    onReach, onFinish を設定した時点ですでに関数の実行が完了していた場合は、そのときにコールバックが呼ばれます。 したがってコールバックはどの状況で設定したとしても必ず1回呼ばれます。 (呼ばれたあとにコールバックを再設定したりしても2度目が呼ばれることはありません)

  • C wcfFuncRunAsync, (2.0 wcfFuncRunAsyncW) で関数を呼び出し、完了を待たずに続行します。 受け取った wcfPromise を使って、 wcfFuncGetResult, (2.0 wcfFuncGetResultW) 後から関数の戻り値や例外を取得できます。

    wcfMultiVal args[3] = {
    wcfValI(42),
    wcfValD(1.5),
    wcfValS("aaa"),
    };
    wcfPromise *async_res;
    wcfFuncRunAsync(wcli_, "a", "b", args, 3, &async_res);
    int ret = wcfFuncGetResult(async_res, &ans);
    // int ret = wcfFuncWaitResult(async_res, &ans);
    // ex.) ret = WCF_OK, ans->as_double = 123.45
    wcfStatus wcfDestroy(void *ptr)
    wcfの関数から取得したポインタのデータを破棄
    Definition client.cc:105
    wcfStatus wcfFuncGetResult(wcfPromise *async_res, wcfMultiVal **result)
    非同期で呼び出した関数の実行結果を取得
    Definition func.cc:277
    wcfStatus wcfFuncRunAsync(wcfClient *wcli, const char *member, const char *field, const wcfMultiVal *args, int arg_size, wcfPromise **async_res)
    関数を非同期で呼び出す
    Definition func.cc:266
    wcfMultiVal wcfValS(const char *value)
    文字列型のwcfMultiValを構築
    Definition func.cc:251
    void wcfPromise
    Definition def_types.h:15
    • (ver1.11まで wcfAsyncFuncResult 型でしたが ver2.0で wcfPromise に名前変更しました)
    • 関数の実行がまだ完了していなければwcfFuncGetResultはWCF_NOT_RETURNEDを返します。
    • 完了していれば、wcfFuncGetResultはWCF_OKを返し、結果が wcfMultiVal 型で取得できます。
      • このとき wcfPromise オブジェクトは破棄され使えなくなります (再度 wcfFuncGetResult を呼ぶことはできません)
      • 1.7 また、受け取った wcfMultiVal オブジェクトは、不要になったら wcfDestroy で破棄してください。
    • 2.0 戻り値を取得する必要がない場合は、 wcfDestroy でwcfPromiseも破棄することができます。

    wcfFuncWaitResult, (2.0 wcfFuncWaitW) は関数の実行が完了し結果が返ってくるまで待機します。

    Warning
    2.0 wcfFuncWaitResult() が結果を受信するためには wcfSync() が必要なため、別スレッドでwcfSync()が呼ばれていなければデッドロックします。

  • JavaScript

    Note
    1.8 C++の Promise 型に合わせて名前変更しました。 以前の名前もまだ使えます。

    Func.runAsync() で関数を呼び出すと、戻り値として AsyncFuncResult FuncPromise クラスのオブジェクトが返り、後から関数の戻り値や例外を取得できます。

    AsyncFuncResult FuncPromise からは started reach と result finish が取得できます。 いずれもPromise型で、awaitで待機したり、then()とcatch()でコールバックを設定できます。

    • reach (started) は対象の関数が存在して実行が開始したときにtrueになり、指定したクライアントまたは関数が存在しなかった場合falseとなります。
      • 1.8 runAsync呼び出し時にクライアントがサーバーに接続していなかった場合は、関数呼び出しメッセージを送信することなく即座にfalseが返ります
    • finish (result) は実行が完了したときに返ります。関数の戻り値を返すか、または発生した例外のメッセージを含むErrorでrejectします。
      • 1.8 Rejectする値は常にError型になっています。 (1.7以前は関数がthrowしたオブジェクトをそのまま返していた)
    import { FuncPromise } from "webcface";
    const res: FuncPromise = wcli.member("foo").func("hoge").runAsync(1, "aa");
    res.reach.then((found: boolean) => {
    if (found) {
    // 関数hogeが存在し、実行が開始された
    } else {
    // 関数hogeが存在しないか未接続で呼び出し失敗
    }
    });
    res.finish.then((ret: number | boolean | string) => {
    // ret が戻り値
    }).catch((e) => {
    // (e as Error).message がエラーメッセージ
    });
  • Python Func.run_async() で関数を呼び出すと、 戻り値として AsyncFuncResult 2.0 Promise クラスのオブジェクトが返り、 後から関数の戻り値や例外を取得できます。

    2.0 Promiseでは以下のメソッドが使用可能です。

    • reached: 関数呼び出しのメッセージが相手のクライアントに到達したらTrue、それまでの間はFalseです。
      • wait_reach(): reached がTrueになるまで待機します。 timeoutを指定することもできます。
    • found: reachedがTrueになった後、相手のクライアントが関数の実行を開始したらTrue、指定したクライアントまたは関数が存在しなかった場合Falseです。
      • reached がFalseの間はFalseです。
      • run_async呼び出し時にクライアントがサーバーに接続していなかった場合は、関数呼び出しメッセージを送信することなく即座にFalseになります
    • finished: 関数の実行が完了し戻り値かエラーメッセージを受け取ったらTrue、それまでの間はFalseです。
      • wait_finish(): finished()がTrueになるまで待機します。 timeoutを指定することもできます。
    • response: 関数の戻り値です。 int, float, bool, str型のいずれかで返ります
    • rejection: 関数が例外を返した場合そのエラーメッセージを表す文字列です。 またその場合 is_error がTrueになります。
    res = wcli.member("foo").func("hoge").run_async(1, "aa")
    res.wait_reach()
    if res.found:
    # 関数hogeが存在し、実行が開始された
    res.wait_finish()
    if res.is_error:
    # res.rejection がエラーメッセージ
    else:
    # res.response が戻り値
    else:
    関数hogeが存在しないか未接続で呼び出し失敗
    Warning
    2.0 上の例のようにwait_reach(), wait_finish() などで結果が返ってくるまで待機することができますが、 これらが結果を受信するためには Client.sync() が必要なため、別スレッドでsync()が呼ばれていなければデッドロックします。

    • on_reach(), on_finish() で値が返ってきたときに実行されるコールバックを設定することができます。
      • 引数にはそのPromise自身が渡されます
      • eventのコールバックと同様、デコレータとして使ってコールバックを設定することもできます。
      • コールバックは Client.sync() の中から呼び出されます。
        res = wcli.member("foo").func("hoge").run_async(1, "aa")
        @res.on_reach
        def on_reach(res: Promise):
        if res.found:
        # 関数hogeが存在し、実行が開始された
        else:
        # 関数hogeが存在しないか未接続で呼び出し失敗
        @res.on_finish
        def on_finish(res: Promise):
        if res.is_error:
        # res.rejection がエラーメッセージ
        else:
        # res.response が戻り値
        Note
        on_reach, on_finish を設定した時点ですでに関数の実行が完了していた場合は、そのときにコールバックが呼ばれます。 したがってコールバックはどの状況で設定したとしても必ず1回呼ばれます。 (呼ばれたあとにコールバックを再設定したりしても2度目が呼ばれることはありません)

    Func.run() は関数を呼び出し、結果が返ってくるまで待機します。 例外が返ってきた場合はRuntimeErrorを、また呼び出しに失敗した場合は webcface.FuncNotFoundError をraiseします。

    result = wcli.member("foo").func("hoge").run(1, "aa")
    • wait_reach(), wait_finish() と同様 Client.sync() が呼ばれていないとデッドロックするので注意してください。

    Funcオブジェクトに()と引数をつけて直接呼び出すことでも同様に実行できます。 (Func.__call__)

AsyncFuncResult.started と result (ver2.0からdeprecated)

  • C++

    AsyncFuncStarted::started と AsyncFuncResult::result はstd::shared_futureであり、取得できるまで待機するならget(), ブロックせず完了したか確認したければwait_for()などが使えます。

    • started は対象の関数が存在して実行が開始したときにtrueになり、指定したクライアントまたは関数が存在しなかった場合falseとなります。
      • 2.0 runAsync呼び出し時にクライアントがサーバーに接続していなかった場合は、関数呼び出しメッセージを送信することなく即座にfalseになります
    • result は実行が完了したときに返ります。関数の戻り値、または発生した例外の情報を含んでいます。
      • 実行した関数が例外を返した場合はresult.get()がstd::runtime_errorを投げます。
    • 2.0 started.get() や result.get() はver2.0以降デッドロックする可能性があります。 詳細は上に書かれている waitReach(), waitFinish() の注意を参照してください
  • Python AsyncFuncResultからは started と result が取得できます。

    • started は対象の関数が存在して実行が開始したときにtrueになり、指定したクライアントまたは関数が存在しなかった場合falseとなります。
    • result は実行が完了したときに返ります。関数の戻り値、または発生した例外の情報を含んでいます。

    startedとresultは取得できるまで待機するgetterです。例外の場合はresultの取得時に投げます。 また、取得可能になったかどうかをstarted_readyとresult_readyで取得できます。 詳細は webcface.AsyncFuncResult を参照

CallbackListを返す AsyncFuncResult::onStarted(), onResult() (C++ ver1.11)

1.11 onStarted(), onResult() で値が返ってきたときに実行されるイベントが取得でき、コールバックを設定することができます。 (eventpp::CallbackList 型の参照で返ります)

AsyncFuncResult res = wcli.member("foo").func("hoge").runAsync(1, "aa");
res.onStarted().append([](bool started){
std::cout << "func hoge() " << started ? "started" : "not started" << std::endl;
});
res.onResult().append([](std::shared_future<webcface::ValAdaptor> result){
try{
double ans = result.get();
}catch(const std::exception &e){
std::cout << e.what() << std::endl;
}
});

C++の Func::run(), Cの wcfFuncRun() (ver2.0からdeprecated)

  • C++ Func::run() で関数を実行できます。引数を渡すこともでき、戻り値もそのまま返ってきます。 他クライアントの関数も同様にrun()で実行させることができます。

    実行した関数が例外を投げた場合、また引数の個数が一致しない場合などはrun()が例外を投げます。

    対象のクライアントと通信できない場合、また指定した関数が存在しない場合は webcface::FuncNotFoundError を投げます。

    double ans = wcli.member("foo").func("hoge").run(1, "aa");

    Funcオブジェクトに()と引数をつけて直接呼び出すことでも同様に実行できます。 (Func::operator())

    戻り値は webcface::ValAdaptor 型で返ります。 整数、実数、bool、stringにキャストできます。
    1.10 また、明示的にキャストするなら asStringRef()(const参照), asString(), asBool(), as<整数or実数型>() も使えます。
    2.0 asWStringRef(), asWString(), asDouble(), asInt(), asLLong() も使えます。

    Warning
    start()を呼んで通信を開始する前にrun()を呼び出してしまうとデッドロックします。

  • C

    wcfMultiVal args[3] = {
    wcfValI(42), // int
    wcfValD(1.5), // double
    wcfValS("aaa"), // string
    };
    int ret = wcfFuncRun(wcli_, "a", "b", args, 3, &ans);
    // ex.) ret = WCF_OK, ans->as_double = 123.45
    wcfStatus wcfFuncRun(wcfClient *wcli, const char *member, const char *field, const wcfMultiVal *args, int arg_size, wcfMultiVal **result)
    関数を呼び出す
    Definition func.cc:256

    関数が存在しない場合WCF_NOT_FOUNDを返します。 関数が例外を投げた場合WCF_EXCEPTIONを返し、ret->as_strにエラーメッセージが入ります。

    1.7 結果が格納されているポインタは、不要になったら wcfDestroy(ans); で破棄してください。

    Warning
    wcfStart()を呼んで通信を開始する前にwcfFuncRun()を呼び出してしまうとデッドロックします。

Previous Next
5-2. Text 5-4. View