diff --git a/BotSharp.Channel.FacebookMessenger/BotSharp.Channel.FacebookMessenger.csproj b/BotSharp.Channel.FacebookMessenger/BotSharp.Channel.FacebookMessenger.csproj
new file mode 100644
index 00000000..1add5556
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/BotSharp.Channel.FacebookMessenger.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BotSharp.Channel.FacebookMessenger/Controllers/FacebookMessengerController.cs b/BotSharp.Channel.FacebookMessenger/Controllers/FacebookMessengerController.cs
new file mode 100644
index 00000000..458a84ba
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Controllers/FacebookMessengerController.cs
@@ -0,0 +1,114 @@
+using BotSharp.Channel.FacebookMessenger.Models;
+using BotSharp.Platform.Models;
+using EntityFrameworkCore.BootKit;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Serialization;
+using RestSharp;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BotSharp.Channel.FacebookMessenger.Controllers
+{
+ [Route("v1/[controller]")]
+ public class FacebookMessengerController : ControllerBase
+ {
+ [HttpGet("{agentId}")]
+ public ActionResult Verify([FromRoute] string agentId)
+ {
+ var mode = Request.Query.ContainsKey("hub.mode") ? Request.Query["hub.mode"].ToString() : String.Empty;
+ var token = Request.Query.ContainsKey("hub.verify_token") ? Request.Query["hub.verify_token"].ToString() : String.Empty;
+ var challenge = Request.Query.ContainsKey("hub.challenge") ? Request.Query["hub.challenge"].ToString() : String.Empty;
+
+ if (mode == "subscribe")
+ {
+ var dc = new DefaultDataContextLoader().GetDefaultDc();
+ var config = dc.Table().FirstOrDefault(x => x.AgentId == agentId && x.Platform == "Facebook Messenger");
+
+ return config.VerifyToken == token ? Ok(challenge) : Ok(agentId);
+ }
+
+ return BadRequest();
+ }
+
+ [HttpPost("{agentId}")]
+ public async Task CallbackAsync([FromRoute] string agentId)
+ {
+ WebhookEvent body;
+ IWebhookMessageBody response = null;
+
+ using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
+ {
+ var json = await reader.ReadToEndAsync();
+ body = JsonConvert.DeserializeObject(json);
+ }
+
+ body.Entry.ForEach(entry =>
+ {
+ entry.Messaging.ForEach(msg =>
+ {
+ // received text message
+ if (msg.Message.ContainsKey("text"))
+ {
+ OnTextMessaged(agentId, new WebhookMessage
+ {
+ Sender = msg.Sender,
+ Recipient = msg.Recipient,
+ Timestamp = msg.Timestamp,
+ Message = msg.Message.ToObject()
+ });
+ }
+ });
+
+ });
+
+ return Ok();
+ }
+
+ private void OnTextMessaged(string agentId, WebhookMessage message)
+ {
+ Console.WriteLine($"OnTextMessaged: {message.Message.Text}");
+
+ /*var ai = new ApiAi();
+ var agent = ai.LoadAgent(agentId);
+ ai.AiConfig = new AIConfiguration(agent.ClientAccessToken, SupportedLanguage.English) { AgentId = agentId };
+ ai.AiConfig.SessionId = message.Sender.Id;
+ var aiResponse = ai.TextRequest(new AIRequest { Query = new String[] { message.Message.Text } });
+
+ var dc = new DefaultDataContextLoader().GetDefaultDc();
+ var config = dc.Table().FirstOrDefault(x => x.AgentId == agentId && x.Platform == "Facebook Messenger");
+
+ SendTextMessage(config.AccessToken, new WebhookMessage
+ {
+ Recipient = message.Sender.ToObject(),
+ Message = new WebhookTextMessage
+ {
+ Text = String.IsNullOrEmpty(aiResponse.Result.Fulfillment.Speech) ? aiResponse.Result.Action : aiResponse.Result.Fulfillment.Speech
+ }
+ });*/
+ }
+
+ private void SendTextMessage(string accessToken, WebhookMessage body)
+ {
+ var client = new RestClient("https://graph.facebook.com");
+
+ var rest = new RestRequest("v2.6/me/messages", Method.POST);
+ string json = JsonConvert.SerializeObject(body,
+ new JsonSerializerSettings
+ {
+ ContractResolver = new CamelCasePropertyNamesContractResolver(),
+ NullValueHandling = NullValueHandling.Ignore
+ });
+
+ rest.AddParameter("application/json", json, ParameterType.RequestBody);
+ rest.AddQueryParameter("access_token", accessToken);
+
+ var response = client.Execute(rest);
+ }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/IWebhookMessageBody.cs b/BotSharp.Channel.FacebookMessenger/IWebhookMessageBody.cs
new file mode 100644
index 00000000..19d72ace
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/IWebhookMessageBody.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger
+{
+ public interface IWebhookMessageBody
+ {
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookEvent.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookEvent.cs
new file mode 100644
index 00000000..d4ba1d72
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookEvent.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookEvent
+ {
+ public string Object { get; set; }
+ public List Entry { get; set; }
+ }
+
+
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookEventEntry.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookEventEntry.cs
new file mode 100644
index 00000000..4889fb97
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookEventEntry.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookEventEntry
+ {
+ public string Id { get; set; }
+ public long Time { get; set; }
+ public List Messaging { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookMessage.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessage.cs
new file mode 100644
index 00000000..e06642f7
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessage.cs
@@ -0,0 +1,29 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookMessage
+ {
+ public WebhookMessageSender Sender { get; set; }
+
+ public WebhookMessageRecipient Recipient { get; set; }
+
+ public long Timestamp { get; set; }
+
+ public JObject Message { get; set; }
+ }
+
+ public class WebhookMessage where TWebhookMessage : IWebhookMessageBody
+ {
+ public WebhookMessageSender Sender { get; set; }
+
+ public WebhookMessageRecipient Recipient { get; set; }
+
+ public long Timestamp { get; set; }
+
+ public TWebhookMessage Message { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageQuickReply.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageQuickReply.cs
new file mode 100644
index 00000000..b67f9a23
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageQuickReply.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookMessageQuickReply
+ {
+ public String Payload { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageRecipient.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageRecipient.cs
new file mode 100644
index 00000000..cba0f51a
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageRecipient.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookMessageRecipient
+ {
+ ///
+ /// PAGE_ID
+ ///
+ public String Id { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageSender.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageSender.cs
new file mode 100644
index 00000000..888aadfa
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookMessageSender.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookMessageSender
+ {
+ ///
+ /// PSID
+ ///
+ public String Id { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/Models/WebhookTextMessage.cs b/BotSharp.Channel.FacebookMessenger/Models/WebhookTextMessage.cs
new file mode 100644
index 00000000..16d0fa73
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/Models/WebhookTextMessage.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BotSharp.Channel.FacebookMessenger.Models
+{
+ public class WebhookTextMessage : IWebhookMessageBody
+ {
+ public string Mid { get; set; }
+ public String Text { get; set; }
+ [JsonProperty("quick_reply")]
+ public WebhookMessageQuickReply QuickReply { get; set; }
+ }
+}
diff --git a/BotSharp.Channel.FacebookMessenger/ModuleInjector.cs b/BotSharp.Channel.FacebookMessenger/ModuleInjector.cs
new file mode 100644
index 00000000..b0d23723
--- /dev/null
+++ b/BotSharp.Channel.FacebookMessenger/ModuleInjector.cs
@@ -0,0 +1,22 @@
+using BotSharp.Core.Modules;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace BotSharp.Channel.FacebookMessenger
+{
+ public class ModuleInjector : IModule
+ {
+ public void ConfigureServices(IServiceCollection services, IConfiguration config)
+ {
+
+ }
+
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env/*, IOptions senparcSetting, IOptions senparcWeixinSetting*/)
+ {
+
+ }
+ }
+}
diff --git a/BotSharp.WebHost/BotSharp.WebHost.csproj b/BotSharp.WebHost/BotSharp.WebHost.csproj
index b4981ca6..9cb8cb19 100644
--- a/BotSharp.WebHost/BotSharp.WebHost.csproj
+++ b/BotSharp.WebHost/BotSharp.WebHost.csproj
@@ -84,6 +84,7 @@
+
diff --git a/BotSharp.WebHost/Settings/app.json b/BotSharp.WebHost/Settings/app.json
index 6ae24b88..486cfadc 100644
--- a/BotSharp.WebHost/Settings/app.json
+++ b/BotSharp.WebHost/Settings/app.json
@@ -1,5 +1,5 @@
{
- "version": "0.1.0",
+ "version": "0.2.0",
"assemblies": "BotSharp.Core",
"platformModuleName": "DialogflowAi",
@@ -13,6 +13,10 @@
{
"Name": "WeixinChannel",
"Type": "BotSharp.Channel.Weixin"
+ },
+ {
+ "Name": "FacebookMessengerChannel",
+ "Type": "BotSharp.Channel.FacebookMessenger"
}
]
}
diff --git a/BotSharp.sln b/BotSharp.sln
index 98c3c7d6..c803e238 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Platform.Dialogflo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Channel.Weixin", "BotSharp.Channel.Weixin\BotSharp.Channel.Weixin.csproj", "{D93BD270-10A6-4EFB-938D-508FD2EAC1E0}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Channel.FacebookMessenger", "BotSharp.Channel.FacebookMessenger\BotSharp.Channel.FacebookMessenger.csproj", "{22C52A04-581B-4186-8C04-0CD359FA568A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
ARTICULATE|Any CPU = ARTICULATE|Any CPU
@@ -205,6 +207,30 @@ Global
{D93BD270-10A6-4EFB-938D-508FD2EAC1E0}.Test|Any CPU.Build.0 = Debug|Any CPU
{D93BD270-10A6-4EFB-938D-508FD2EAC1E0}.Test|x64.ActiveCfg = Debug|Any CPU
{D93BD270-10A6-4EFB-938D-508FD2EAC1E0}.Test|x64.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.ARTICULATE|Any CPU.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.ARTICULATE|Any CPU.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.ARTICULATE|x64.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.ARTICULATE|x64.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Debug|x64.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.DIALOGFLOW|Any CPU.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.DIALOGFLOW|Any CPU.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.DIALOGFLOW|x64.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.DIALOGFLOW|x64.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.RASA|Any CPU.ActiveCfg = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.RASA|Any CPU.Build.0 = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.RASA|x64.ActiveCfg = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.RASA|x64.Build.0 = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Release|x64.ActiveCfg = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Release|x64.Build.0 = Release|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Test|Any CPU.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Test|Any CPU.Build.0 = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Test|x64.ActiveCfg = Debug|Any CPU
+ {22C52A04-581B-4186-8C04-0CD359FA568A}.Test|x64.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE