I want to get a list of all (active) resources of a person in my roster.
So for example "user1#gmail.com" I'd like to get something like {'gmail', 'pidgin'} if that user was currently logged in via GMail ('user1#gmail.com/gmail') and Pidgin.
Is this possible with Smack? I know that some clients show this information and e.g. XMPPHP supports something like getResources(), but XMPPHP is for PHP and doesn't work for Google Talk so that doesn't help me much.
Best regards
With Smack you need to track Presence packets as they are received. The "from" of the received packets will contain the resources for the JIDs of users.
For example:
private XMPPConnection connection;
private PresenceListener listener = new PresenceListener();
public void setConnection(XMPPConnection connection) {
this.connection = connection;
}
public void createPresenceListener() {
connection.addPacketListener(listener, new PacketTypeFilter(Presence.class));
}
public static class PresenceListener implements PacketListener {
public void processPacket(Packet packet) {
Presence presence = (Presence) packet;
if (presence.getType() == null || presence.getType() == Presence.Type.available) {
String from = presence.getFrom();
if (from != null && from.lastIndexOf("/") > 0) {
String resource = from.substring(from.lastIndexOf("/") + 1);
// from here you can track all active resources
}
}
}
}
Related
I am using both packages Photon Pun2 and Photon Chat in my application. But i can't find any way to send or receive images, audio, or video via private message.
Yes there is ... However, it is quite limited.
Exactly how big are the things you have to send?
Chat
In Photon Chat Message payload is limited to something between 400.000 and 500.000 bytes. I didn't test it more in detail but if your message size hits a certain limit you are immediately disconnected without a proper feadback for the reason ^^
See Photon Chat Intro
Example
public class MyChatListner : IChatClientListener
{
public event Action<byte[]> OnReceived;
private ChatClient cient;
public void Initialize()
{
client = new ChatClient(this);
client.ChatRegion = ...;
client.Connect(....);
}
// Sicne you already work with the chat you should know but anyway
// This has to be called continuously (who knows in what intervals)
public void Heartbeat()
{
client.Service();
}
public void SendData(string recipient, byte[] data)
{
client.SendPrivateMessage(recipient, data);
}
public void OnPrivateMessage(string sender, object message, string channelName)
{
OnReceived?.Invoke((byte[])message);
}
// also will have to implement the other methods from IChatClientListener ...
}
PUN2
In Pun2 I don't know if such a limit exists but it will definitely delay everything else until the file is fully received. Here you can directly send and receive byte[] via PhotonNetwork.RaiseEvent and OnEvent (via the interface IOnEventCallback)
Example
// doesn't even have to be monobehaviour necessarily
public class FileTransmitter : IOnEventCallback
{
private const byte eventID = 42;
public event Action<byte[]> OnReceived;
public void Enable()
{
PhotonNetwork.AddCallbackTarget(this);
}
public void Disable()
{
PhotonNetwork.RemoveCallbackTarget(this);
}
public void SendData(byte[] data, SendOptions sendoptions, RaiseEventOptions raiseEventOptions = null)
{
PhotonNetwork.RaiseEvent(eventID, data, raiseEventOptions, sendoptions);
}
public void OnEvent(EventData photonEvent)
{
if(photonEvent.Code != eventID) return;
var data = (byte[]) photonEvent.CustomData;
OnReceived?.Invoke(data);
}
}
Alternatively you can of course also use the RPC directly and use e.g.
public class FileTransfer : MonoBehaviourPun
{
[PunRPC]
void ChatMessage(string fileName, byte[] content)
{
// e.g.
File.WriteAllBytes(Path.Combine(Application.persistentDataPath, fileName), content);
}
public void SendFile(string fileName, byte[] content, PhotonPlayer targetPlayer)
{
photonView.RPC(nameof(ChatMessage), targetPlayer, fileName, content);
}
}
Either way personally what I did was using only one single byte[] and encoded all required information into it. Photon will do this anyway with all parameters but if you already know exactly what data you send and how to deserialize it it is way more efficient to do it yourself e.g. in a Thread/Task. Then on the receiver side I deserialized these into the individual information again.
It's possible and working just fine (even though you should watch for the limits as #derHugo said). My implementation uses RPC to send an array of bytes using Texture2D.EncodeToPNG and then decoding it on the clients upon receiving it.
To convert the byte array back into the image, you can use Texture2D.LoadImage method.
The approach is similar for sending other multimedia types, just the encoding/decoding methods are different.
PhotonStream allows you to stream any byte[] data though the network.
In theory, any data type can be converted in to byte[], and decode them on the receiver side.
Below example script is just an example with minimal setup.
reference from: https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/
It's also possible to live stream video, audio and remote commands with popular third party plugins like FMETP STREAM, which has native fast encoder for capturing your Game View and Desktop View in real time, even compatible with mobile and VR devices.
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// ref: https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/
public class FMStreamPUN : Photon.Pun.MonoBehaviourPun, IPunObservable {
private Queue<byte[]> appendQueueSendData = new Queue<byte[]>();
public int appendQueueSendDataCount { get { return appendQueueSendData.Count; } }
public UnityEventByteArray OnDataByteReadyEvent = new UnityEventByteArray();
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
//Send the meta data of the byte[] queue length
stream.SendNext(appendQueueSendDataCount);
//Sending the queued byte[]
while(appendQueueSendDataCount > 0) {
byte[] sentData = appendQueueSendData.Dequeue();
stream.SendNext(sentData);
}
}
if (stream.IsReading) {
if (!photonView.IsMine) {
//Get the queue length
int streamCount = (int)stream.ReceiveNext();
for (int i = 0; i < streamCount; i++) {
//reading stream one by one
byte[] receivedData = (byte[])stream.ReceiveNext();
OnDataByteReadyEvent.Invoke(receivedData);
}
}
}
}
public void Action_SendData(byte[] inputData) {
//inputData(byte[]) is the encoded byte[] from your encoder
//doesn't require any stream, when there is only one player in the room
if(PhotonNetwork.CurrentRoom.PlayerCount > 1) appendQueueSendData.Enqueue(inputData);
}
}
Is there a work-around to get Spring to handle incoming messages from XMPP? I have tried many different configurations to get an inbound-channel-adapter to respond to incoming XMPP messages and nothing happens. I know that they show up at the Spring Integration layer (I can see that in the logs) but they are ignored. Is there any way to get them into my application layer? I hope to avoid needing to make changes to Spring Integration itself if I can.
Here is my integration configuration:
<int-xmpp:inbound-channel-adapter id="gcmIn"
channel="gcmInChannel"
xmpp-connection="gcmConnection"
auto-startup="true"
/>
<bean id="inboundBean" class="example.integration.GcmInputHandler"/>
<int:service-activator input-channel="gcmInChannel" output-channel="nullChannel" ref="inboundBean" method="handle"/>
Using the outbound-channel-adapter works fine. I can send messages over GCM 100% easily. But inbound does nothing, even though I know the messages are coming in.
Thanks
Not a very clean one, you would need to overwrite the ChatMessageListeningEndpoint, which drops all empty body messages.
This one needs then to be used as inbound-channel adapter in your config.
In addition you need to register the GCM package extension on the Smack Provider Manager, otherwise you lose the JSON message.
Working on a sample project -- so if you need more help let me know and I will post a link as soon it works somehow in a understandable way.
Here a sample GCM Input Adapter
public class GcmMessageListeningEndpoint extends ChatMessageListeningEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(GcmMessageListeningEndpoint.class);
#Setter
protected PacketListener packetListener = new GcmPacketListener();
protected XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
public GcmMessageListeningEndpoint(XMPPConnection connection) {
super(connection);
ProviderManager.addExtensionProvider(GcmPacketExtension.GCM_ELEMENT_NAME, GcmPacketExtension.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
#Override
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
super.setHeaderMapper(headerMapper);
this.headerMapper = headerMapper;
if (this.headerMapper == null) throw new IllegalArgumentException("Null XmppHeaderMapper isn't supported!");
}
public String getComponentType() {
return "xmpp:inbound-channel-adapter-gcm";
}
#Override
protected void doStart() {
Assert.isTrue(this.initialized, this.getComponentName() + " [" + this.getComponentType() + "] must be initialized");
this.xmppConnection.addPacketListener(this.packetListener, null);
}
#Override
protected void doStop() {
if (this.xmppConnection != null) {
this.xmppConnection.removePacketListener(this.packetListener);
}
}
class GcmPacketListener implements PacketListener {
#Override
public void processPacket(Packet packet) throws NotConnectedException {
if (packet instanceof org.jivesoftware.smack.packet.Message) {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) packet;
Map<String, ?> mappedHeaders = headerMapper.toHeadersFromRequest(xmppMessage);
sendMessage(MessageBuilder.withPayload(xmppMessage).copyHeaders(mappedHeaders).build());
} else {
LOG.warn("Unsuported Packet {}", packet);
}
}
}
}
And here the new configuration for the inbound-channel-adapter remove the one in XML:
#Bean
public GcmMessageListeningEndpoint inboundAdpater(XMPPConnection connection, MessageChannel gcmInChannel) {
GcmMessageListeningEndpoint endpoint = new GcmMessageListeningEndpoint(connection);
endpoint.setOutputChannel(gcmInChannel);
return endpoint;
}
I am looking for something I would call CounterObservable One side would count the numbers on it and other side would be the observer side that will receive notification every time total count changes.
In other words I will have something like this
public CounterObservable totalMailsReceived = new CounterObservable(0);
public void OnNewMail(Mail mail)
{
totalMailsReceived++;
///Rest of the code goes here
}
on the Observer side I will have
mailManager.totalMailsReceived.Subscribe(count => labelCount.Text = count.ToString());
Or if I want to go real classy, I would use Paul Betts' ReactiveUI like the following
mailManager.totalMailsReceived.ToProperty(x => x.TotalMailsReceived);
I have so far found nothing in Rx that could help me. But I figured if I create my own class that implements IObservable<int>. I am thinking of leveraging the Sample MSDN Code for IObservable implementation for that.
My questions are
1. Is that MSDN Sample thread-safe ?
2. Is there really nothing in Rx already that does what I am trying to do ?
Just use a BehaviorSubject:
public class MailServer
{
private BehaviorSubject<int> _count = new BehaviorSubject<int>(0);
public IObservable<int> TotalMailsReceived
{
get { return _count; }
}
public void OnNewMail(Mail mail)
{
_count.OnNext(_count.Value + 1);
}
}
Or, if you decide to go deeper into Rx, so that you are just observing a Mail stream, then you can use Scan operator which is good for that and Publish to remember the most recent value and multicast it to all subscribers.
You can write this new extension method:
public IObservable<T> RunningTotal<T>(this IObservable<T> source)
{
return source.Scan(0, sum => sum + 1);
}
And use it like so:
public class MailServer
{
private IConnectableObservable<int> _total;
private IDisposable _subscription;
public MailServer(IObservable<Mail> incomingMail)
{
_total = incomingMail.RunningTotal().Publish(0);
_subscription = _total.Connect();
}
public IObservable<int> TotalMailsReceived
{
get { return _total; }
}
}
I have a problem when running multiple impersonations of users in EWS, when I want to recieve notifications on each of the impersonated persons calendars (possible 100 persons).
Currently I have an outlook account who have rights to impersonate all other users, and all the ExchangeService-objects get this accounts credentials
Short version is, that when I try to bind to an appointment via the unique ID it works as long as I only have one thread running. When I start a new thread containing a new Exchangeservice with its own subscription I dont recieve any response on the Appointment.Bind()-request.
When I run two instances of my program with only 1 thread in each it works fine, but as soon as I start a new thread with a new ExchangeService the Appointment.Bind() doesnt give any response.
The weird part about this is, that it worked fine two weeks ago, but suddenly it stopped working and I didnt change my code.
I have created a quick demo of my problem:
class Program
{
static void Main(string[] args)
{
var x = new OutlookListener("user1#server.com");
var y = new OutlookListener("user2#server.com");
new Thread(x.Start).Start();
new Thread(y.Start).Start();
while (true)
{
}
}
}
class OutlookListener
{
private ExchangeService _ExchangeService;
private AutoResetEvent _Signal;
public OutlookListener(string emailToImp)
{
_ExchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP1)
{
Credentials = new NetworkCredential("superuser#server.com", "password"),
Url = new Uri("exchangeUrl"),
ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, emailToImp)
};
}
public void Start()
{
var subscription = _ExchangeService.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.Calendar },
EventType.Created);
var connection = CreateStreamingSubscription(_ExchangeService, subscription);
Console.Out.WriteLine("Subscription created.");
_Signal = new AutoResetEvent(false);
_Signal.WaitOne();
subscription.Unsubscribe();
connection.Close();
}
private StreamingSubscriptionConnection CreateStreamingSubscription(ExchangeService service, StreamingSubscription subscription)
{
var connection = new StreamingSubscriptionConnection(service, 30);
connection.AddSubscription(subscription);
connection.OnNotificationEvent += OnNotificationEvent;
connection.OnSubscriptionError += OnSubscriptionError;
connection.OnDisconnect += OnDisconnect;
connection.Open();
return connection;
}
private void OnNotificationEvent(object sender, NotificationEventArgs args)
{
// Extract the item ids for all NewMail Events in the list.
var newMails = from e in args.Events.OfType<ItemEvent>()
where e.EventType == EventType.Created
select e.ItemId;
foreach (var newMail in newMails)
{
var appointment= Appointment.Bind(_ExchangeService, newMail); //This is where I dont get a response!
Console.WriteLine(appointment.Subject);
}
}
private void OnSubscriptionError(object sender, SubscriptionErrorEventArgs args)
{
}
private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
{
}
}
Any suggestions?
I have had the same issue and found that my EWS solution was limited by two factors.
The System.Net.ServicePointManager.DefaultConnectionLimit is by default set to 2, which I've changed to 20 which i beleive to match the throttling policy of Exchange Online.
Second the ConnectionGroupName property on the ExchangeService object can be used to pool connections into different relevant groups which have a limit of concurrent connections cohernet with the DefaultConnectionLimit property.
A way to override the settings is to set the ConnectionGroupName property to a uniquevalue for each ExchangeService object you create.
ExchangeService exchangeService = new ExchangeService()
{
ConnectionGroupName = Guid.NewGuid().ToString()
};
Why do you need multiple threads ?
In my case , I have created a dictionary of Services based on the smtpaddress for each email I want to impersonate, and I subscribe to them all. All can happen in one thread, and all notification from any user will be handled in the OnNotificationEvent .
[THIS CODE IS JUST TO SHOW THE LOGIC AND IS NOT COMPLETE FOR FULL COMPILATION AND RUN]
var service = new ExchangeService(exchangeVersion);
var serviceCred = ((System.Net.NetworkCredential)(((WebCredentials)(Services.First().Value.Credentials)).Credentials));
service.Credentials = new WebCredentials(serviceCred.UserName, serviceCred.Password);
service.AutodiscoverUrl(userSmtp, RedirectionUrlValidationCallback);
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, userSmtp);
Services.Add(userSmtp, service);
Note that Services.First().Value is the service that can impersonate all the other users, and here it is cloned as the number of the user.
After that Subscriptions for the all services (note that now each service is impersonating different user)
foreach (var service in Services.Values)
{
SubscribeToService(service);
}
and the definition for SubscribeToService is as follow
private void SubscribeToService(ExchangeService service)
{
if (service.ImpersonatedUserId == null)
return;
if (service.Url == null)
return;
var serviceName = service.ImpersonatedUserId.Id;
var streamingSubscription =
service.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.DeletedItems, WellKnownFolderName.Calendar },
EventType.FreeBusyChanged, EventType.Moved, EventType.Created, EventType.Modified);
if (!Connections.ContainsKey(service.Url))
{
Connections.Add(service.Url, new StreamingSubscriptionConnection(service, 30));
}
var connection = Connections[service.Url];
CloseConnection(connection);
if (!_subscriptions.ContainsKey(serviceName))
{
_subscriptions.Add(serviceName, streamingSubscription);
connection.AddSubscription(streamingSubscription);
}
}
}
All of this can happen in one single thread, and I hope my answer will help you
Cheers
I'm new to WP7 and coming from iPhone development. On iPhone I'm used to use NSNotificationCenter to notify my program of something. NSNotificationCenter is build-in the framework out of the box. Is there something similar in WP7? I stumbled uppon MVVM-Light Toolkit but I'm not sure how to use it correctly.
What I want to do:
Register to an Notification-Id and do something when Notification-Id is received
Send Notification with Notification-Id and a context (object to pass to observers)
Everyone who registers to the same Notification-Id will be notified
So something like: Registering
NotificationCenter.Default.register(receiver, notification-id, delegate);
Sending:
NotificationCenter.Default.send(notification-id, context);
Example for Registering:
NotificationCenter.Default.register(this, NotifyEnum.SayHello, m => Console.WriteLine("hello world with context: " + m.Context));
Sending ...
NotificationCenter.Default.send(NotifyEnum.SayHello, "stackoverflow context");
Here is how to do with the MVVM Light Toolkit:
Registering:
Messenger.Default.Register<string>(this, NotificationId, m => Console.WriteLine("hello world with context: " + m.Context));
Sending:
Messenger.Default.Send<string>("My message", NotificationId);
Here http://www.silverlightshow.net/items/Implementing-Push-Notifications-in-Windows-Phone-7.aspx you will find a great example on how to use push notification on windows phone 7.
I'm pretty sure that you archive the same result as NSNotificationCenter by creating a singleton which holds a list of observables that implements a specific interface based on your bussiness requirements, or call a lamba, or trigger an event, for each message sent by this singleton you will interate the list of observables and checking the message id, once you find one or more, you can call the interface method, or execute the lambda expression or trigger the event defined to digest the message contents.
Something like below:
public class NotificationCenter {
public static NotificationCenter Default = new NotificationCenter();
private List<KeyValuePair<string, INotifiable>> consumers;
private NotificationCenter () {
consumers = new List<INotifiable>();
}
public void Register(string id, INotifiable consumer) {
consumers.Add(new KeyValuePair(id, consumer));
}
public void Send(String id, object data) {
foreach(KeyValuePair consumer : consumers) {
if(consumer.Key == id)
consumer.Value.Notify(data);
}
}
}
public interface INotifiable {
void Notify(object data);
}
public class ConsumerPage : PhoneApplicationPage, INotifiable {
public ConsumerPage() {
NotificationCenter.Default.Register("event", this);
}
private Notify(object data) {
//do what you want
}
}
public class OtherPage : PhoneApplicationPage {
public OtherPage() {
NotificationCenter.Default.Send("event", "Hello!");
}
}