Skip to content

Instantly share code, notes, and snippets.

@pulyaevskiy
Last active December 14, 2018 05:20
Show Gist options
  • Save pulyaevskiy/800a87ccc8db6c57145f53e8ec01b0b6 to your computer and use it in GitHub Desktop.
Save pulyaevskiy/800a87ccc8db6c57145f53e8ec01b0b6 to your computer and use it in GitHub Desktop.

Revisions

  1. pulyaevskiy revised this gist Dec 14, 2018. 1 changed file with 3 additions and 5 deletions.
    8 changes: 3 additions & 5 deletions main.dart
    Original file line number Diff line number Diff line change
    @@ -32,11 +32,9 @@ void main() {
    conv.ask('Your ssml goes here...');
    }));

    // I'm not sure if you actually need to export a firebase function from this
    // script. Actions documentation never mentioned this.
    // I suspect you'd need separate build targets for actions and for functions
    // which could simply be just separate files in your node/ folder.
    // The below line likely won't compile because [app] has wrong type.
    // This won't actually work currently as firebase_functions_interop expects a Dart function
    // in onRequest. This can be easily fixed by updating the package to support actionssdk
    // or expose native JS object to interact with directly.
    functions['sayNumber'] = functions.https.onRequest(app);
    }

  2. pulyaevskiy created this gist Dec 14, 2018.
    112 changes: 112 additions & 0 deletions main.dart
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,112 @@
    /// This is pseudo-code which drafts possible way of using Google's `actions-on-google` Node.js package.
    /// This code has not been tested, compiled or ran anywhere.
    @JS()
    library actionssdk;

    import 'package:firebase_functions_interop/firebase_functions_interop.dart';
    import 'package:js/js.dart';
    import 'package:js/js_util.dart';
    import 'package:node_interop/node_interop.dart';

    void main() {
    final app = actionssdk(ActionsSDKAppOptions(debug: true));
    // Note that Dart functions cannot be passed to JS as-is and must be
    // wrapped with allowInterop or allowInteropCaptureThis
    app.intent('actions.intent.MAIN', allowInterop((ActionsSDKConversation conv,
    [String input, Argument argument, GoogleRpcStatus status]) {
    conv.ask('Your ssml goes here');
    // If above call fails when deployed we might need to use callMethod:
    callMethod(conv, 'ask', ['Your ssml goes here']);
    // As you can see in firebase_admin_interop and functions interop
    // I abstract away all these details from the user so that they only
    // need to deal with pure Dart.
    }));

    app.intent('actions.intent.MAIN', allowInterop((ActionsSDKConversation conv,
    [String input, Argument argument, GoogleRpcStatus status]) {
    if (input == 'bye') {
    // The `close` method is similar to `ask` method so might need the `callMethod`
    // approach
    conv.close('Goodbye!');
    }
    conv.ask('Your ssml goes here...');
    }));

    // I'm not sure if you actually need to export a firebase function from this
    // script. Actions documentation never mentioned this.
    // I suspect you'd need separate build targets for actions and for functions
    // which could simply be just separate files in your node/ folder.
    // The below line likely won't compile because [app] has wrong type.
    functions['sayNumber'] = functions.https.onRequest(app);
    }

    // This loads Node.js package
    // Note that you need to have it in your package.json
    final ActionsSDKExports _actionsOnGoogleExports = require('actions-on-google');
    // This provides access to the actionssdk only
    final ActionsSDKAppFactory actionssdk = _actionsOnGoogleExports.actionssdk;

    /// Here we define interface of exports provided by Node.js package.
    @JS()
    @anonymous
    abstract class ActionsSDKExports {
    // For this example we only declare the actionssdk binding, but can add more if needed.
    external ActionsSDKApp actionssdk(ActionsSDKAppOptions options);
    }

    typedef ActionsSDKAppFactory = ActionsSDKApp Function(
    ActionsSDKAppOptions options);

    /// Here we define interface that's expected for the actionssdk.
    @JS()
    @anonymous
    abstract class ActionsSDKApp {
    // Rough approximation of method signature from here:
    // https://actions-on-google.github.io/actions-on-google-nodejs/interfaces/actionssdk.actionssdkapp.html#intent
    // [intent] here can be either single value or an array, so had to declare
    // as dynamic
    external ActionsSDKApp intent(
    dynamic intent, ActionsSdkIntentHandler handler);
    }

    // This is how to declare basic JSON-like objects so that it's easy to use
    // On the Dart side. Mostly useful for things like options (this case)
    @JS()
    @anonymous
    abstract class ActionsSDKAppOptions {
    external bool get debug;
    // Must have external factory
    external factory ActionsSDKAppOptions({bool debug});
    }

    /// All the bindings continued...
    /// You have to declare everything you're going to use.
    /// This is rough approximation of signature from here:
    /// https://actions-on-google.github.io/actions-on-google-nodejs/interfaces/actionssdk.actionssdkintenthandler.html
    typedef ActionsSdkIntentHandler = dynamic Function(ActionsSDKConversation conv,
    [String input, Argument argument, GoogleRpcStatus status]);

    @JS()
    @anonymous
    abstract class ActionsSDKConversation {
    // Type definition for ask seems like it could be a variadic function
    // in which case we won't be able to just call `conv.ask('something')` and
    // will have to invoke it using [callMethod].
    external ActionsSDKConversation ask(dynamic responses);
    // The same applies to this method.
    external ActionsSDKConversation close(dynamic responses);
    // ...
    }

    @JS()
    @anonymous
    abstract class Argument {
    // ...
    }

    @JS()
    @anonymous
    abstract class GoogleRpcStatus {
    // ...
    }