DotGadu - protokół Gadu-Gadu w .NET

0

witam

Od jakiegoś czasu w wolnych chwilach pisze sobie bibliotekę do obsługi Gadu-Gadu, dzisiaj wydałem pierwszą wersję, jeżeli ktoś jest zainteresowany to zapraszam na:
http://dotgadu.sourceforge.net/

0

Niezłe - ja też na czymś takim pracuje : zobacz http://www.hakger.xorg.pl --> Sharp HGG. Na razie zrobiłem:

  • wysyłanie / odbieranie wiadomości
  • opisy / statusy
  • lista kontaktów (blokowanie osób itp)
  • wysyłanie sformatowanych wiadomości
  • połączenia konferencyjne
  • zakładanie/usuwanie kont GG / zmiana hasła / zmiana adresu e-mail
  • szukanie osób w katalogu publicznym

propozycja: może "złączymy siły" i będziemy wspierać jeden projekt?

0

propozycja wspierania jednego projektu wydaje sie calkowicie sensowna i na pewno przynioslaby lepsze rezultaty niz rozwijanie dwoch projektow osobno, ale widze ze twoja biblioteka jest w bardziej zaawansowanym stadium rozwoju niz moja, a wiec polaczenie sil prawdopodobnie musialoby oznaczac porzucenie DotGadu na rzecz Sharp HGG, a niestety chcialbym zrobic wlasna biblioteke, glownie ze wzgledow edukacyjnych ;-)

0

No to postanowiłem sprawdzić jak działa ta biblioteka ;) no i napotkałem dziwny problem.
Jeśli zostanie wywołana metoda przez delegacje np. „public void packet(IGaduPacket packet)” a w niej modyfikuje zawartość kontrolki:
" cmbStatus.Items.Add("Wysłano");
cmbStatus.Text = "Wysłano";"
wywala mi wyjatek… a jeśli to usune i umieszcze np MessageBox-a jest wsystko ok. Dlaczego???

private void btnZaloguj_Click(object sender, EventArgs e)
        {
            int nrGG = Int32.Parse(txtNrGG.Text);
                
            GaduServer gaduServer = new GaduServer(nrGG);
                cmbStatus.Items.Add("Łaczy z serverem");
                cmbStatus.Text = "Łaczy z serverem";
            gadu = new Gadu();
            gadu.Reciever.OnLoginOK += new OnLoginOKHandler(loginok);
            gadu.Reciever.OnLoginFailed += new OnLoginFailedHandler(loginfailed);
            gadu.Reciever.OnLoginNeedEmail += new OnLoginNeedEmailHandler(loginneedemail);
            gadu.Sender.OnPacketSended += new OnPacketSendedHandler(packet);
            
            gadu.Connect(gaduServer);
                cmbStatus.Items.Add("Połączono z serverem");
                cmbStatus.Text = "Połączono z serverem";
            gadu.Login(nrGG, mtbHaslo.Text);       
        }

        private void btnWyloguj_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(5000);
            gadu.Logout();
            gadu.Disconnect();
            cmbStatus.Items.Add("Rozłączono");
            cmbStatus.Text = "Rozłączono";
        }

        public void packet(IGaduPacket packet)
        {
            cmbStatus.Items.Add("Wysłano");
            cmbStatus.Text = "Wysłano";
        }

        public void loginok()
        {
            cmbStatus.Items.Add("Zalogowano");
            cmbStatus.Text = "Zalogowano";
        }

        public void loginfailed()
        {
            cmbStatus.Items.Add("Błąd logowania");
            cmbStatus.Text = "Błąd logowania";
        }

        public void loginneedemail()
        {
            cmbStatus.Items.Add("Mail");
            cmbStatus.Text = "Mail";
        }
0

szkoda ze nie napisales jaki jest to wyjatek, ale domyslam sie ze jest to
InvalidOperationException
jest to zwiazane z tym ze w GaduReciever dziala watek, ktory odbiera wszystkie pakiety, kazda delegacja wiec dziala w tym watku, co za tym idzie kiedy w event podstawisz kod modyfikujacy jakas kontrolke, jest ona modyfikowana z watku powolowanego przez GaduReciever, a nie z glownego watku apliacji, pczytaj o:
"How to make cross-thread calls to Windows.Forms Controls"
ew. mozesz pojsc na latwizne i w konstruktorze klasy, ktora jest okienkiem wpisz linike:
CheckForIllegalCrossThreadCalls = false;
problem powinien zniknac, ale polecam polecac poczytac o tym w jakis sposob bezpiecznie modyfikowac Windows.Forms z innych watkow niz glowny

poczytac o tym temacie mozna np. tutaj:
http://msdn2.microsoft.com/pl-pl/library/ms171728(en-us,VS.80).aspx

0

czester21 : podpowiedź: w shgg nie ma takiego wyjątku ;-) - zobacz funkcję PostCallback(). To programista klasy / biblioteki powinien o to zadbać, w końcu wyjątek leci z niej.

0

Hmmmm racja racja czas przysiąść się i poczytać o wielowątkowości ;) w książce Stephen-a C. Perry pt: „C# i .NET” autor pisze „Tworząc formularze Windows i ogólnie interfejsy użytkownika, trzeba pamiętać, że wszystkie kontroli formularza działają w tym samym wątku i należy w nich korzystać tylko z kodu tego wątku. Jeśli działa wiele wątków, danej kontrolki nie należy używać (nawet jeśli jest to techniczne możliwe) w żadnym kodzie oprócz kodu w wątku tej kontrolki. Jest to jedno z przykazań platformy .NET.

Wiec pozwolę sobie trochę pójść na łatwiznę zadać pytanie co mam zrobić żeby zmodyfikować kontrolkę z wątku kontrolek?? Czyli jak wnioskuje z wypowiedzi czester21 z wątku głównego tak?

0

najprosciej zrobic sobie delegacje, tutaj przyklad:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        public delegate void setText(String text);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread=new Thread(new ThreadStart(thread_func));
            thread.Start();
        }

        private void thread_func()
        {
            setText settext = new setText(setText_safe);
            this.Invoke(settext, "abc");
        }

        private void setText_safe(String text)
        {
            textBox1.Text = text;
        }
    }
}

W przykladzie po kliknieciu na przysik zostaje utworzony watek, ktory wykonuje funkcje thread_func(), funkcja thread_func() nie zmienia jednak bezposrednio wartosci lineEdit1 aby nie wywolac bledu, robi to przez delegacje, kluczowym wlasciwie w tym przykladzie jest this.Invoke(), bo to dzieki temu delegacja wykona sie w watku okienka

0

Dzieki. Jak bede miał troche czasu to sprawdze i zabiore się z wielowątkowośc bo mam braki. Wkleje jeszcze co debuger wywala, może pomoże w udoskonaleniu biblioteki ;) bo jak Deti napisał nie powinien wyjątek wywalać.

DotGadu.GaduSenderException was unhandled
Message="Cross-thread operation not valid: Control 'cmbStatus' accessed from a thread other than the thread it was created on."
Source="DotGadu"
StackTrace:
at DotGadu.GaduSender.go() in C:\Documents and Settings\czester21\Pulpit\DotGadu\DotGadu\GaduSender.cs:line 149
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

0
czester21 napisał(a)

najprosciej zrobic sobie delegacje, tutaj przyklad:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        public delegate void setText(String text);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread=new Thread(new ThreadStart(thread_func));
            thread.Start();
        }

        private void thread_func()
        {
            setText settext = new setText(setText_safe);
            this.Invoke(settext, "abc");
        }

        private void setText_safe(String text)
        {
            textBox1.Text = text;
        }
    }
}

W przykladzie po kliknieciu na przysik zostaje utworzony watek, ktory wykonuje funkcje thread_func(), funkcja thread_func() nie zmienia jednak bezposrednio wartosci lineEdit1 aby nie wywolac bledu, robi to przez delegacje, kluczowym wlasciwie w tym przykladzie jest this.Invoke(), bo to dzieki temu delegacja wykona sie w watku okienka

Można też

    private void button1_Click(object sender, EventArgs e)
    {

if (InvokeRequired) {
BeginInvoke(new EventHandler(button1_Click), sender, e);
return;
}
//kod obslugi eventu
}

0

dzisiaj wypuscilem nowa wersje DotGadu, zapraszam na:
http://dotgadu.sourceforge.net/

0

Gratulacje dla obu autorów za dobrą prace :) Mam tylko małe pytanie dla czestera21 - kiedy można się spodziewać obsługi polskich czcionek ;)?

0
Drakon napisał(a)

Gratulacje dla obu autorów za dobrą prace :) Mam tylko małe pytanie dla czestera21 - kiedy można się spodziewać obsługi polskich czcionek ;)?

ups.... zapomnialem ze w Gadu-Gadu wszystko lala w cp1250... poprawiony kod DotGadu juz na svn, w najblizszym czasie sprobuje znalezc troche czasu zeby sprawdzic czy dziala wszystko rowniez na MONO, jezeli bedzie ok to zbuduje paczki i wydam nowa wersje
oprocz wysylania/odbierania wiadomosci poprawilem rowniez zmiany statusow, tam tez zapomnialem o cp1250

0

dzisiaj znalazlem troche czasu na wypuszczenie nowej wersji :)
zapraszam na http://dotgadu.sf.net/

0

A słyszeliście o konkursie na projekt Open Source w .NET? :)

Może trochę więcej szczegółów .. kto, jak, gdzie, kiedy..

0

Witam i gratuluję twórcom świetnego pomysłu.
Mam jednak pytanie co do funkcjonowania jednej z funkcji. Chodzi mianowicie o tzw. "kontynuację" zapytań do katalogu publicznego. Chciałem dla przećwiczenia próbę stworzyć na bazie biblioteki dotgadu własną wyszukiwarkę kontaktów... i poza jednym małym problemem wszystko działa OK. Tym problemem jest parametr "FmStart" (numer, od którego rozpocząć wyszukiwanie, ma znaczenie, gdy kontynuujemy wyszukiwanie - do katalogu publicznego). Wygląda na to że system nie uwzględnia tego parametru w zapytaniach (tzn. niezależnie od tego jaką wartość FmStart podam zawsze dostają takie same wyniki).

Podaję przykładowy kod:

// --------------------------------------------------------------------------------------------------------

class Test
{
private Gadu m_gadu = null;
private int m_searchStart = 0; // Poczatkowa wartosc parametru FmStart.
private int m_count = 10; // Ile razy kontynuowac zapytanie.

public Test()
{
GaduServer gaduServer = new GaduServer("91.197.13.26" , 8074);
m_gadu = new Gadu();
m_gadu.Reciever.OnPubDirReplay += new OnPubDirReplayHandler(PubDirReplay);
m_gadu.Connect(gaduServer);
m_gadu.Login(1111 , "****"); // Wlasne parametry polaczenia do serwera gg :)
}

public void Search()
{
GaduUser gaduUser = new GaduUser();
gaduUser.Name = "Jacek";
gaduUser.FmStart = m_searchStart;
Console.WriteLine(m_count + ". Search from: " + m_searchStart);
m_gadu.PubDir.Search(gaduUser);
}

private void PubDirReplay(GaduPacketPubDir50 gaduPacketPubDirReplay50)
{
List<GaduUser> list = GaduUser.ParsePubDirString(gaduPacketPubDirReplay50.Data);
for (int i = 0 ; i < list.Count ; i++)
{
GaduUser user = list[i];
Console.WriteLine(user.Uin + " , " + user.Name + " , " + user.Nick);
m_searchStart = Math.Max(user.Uin + 1 , m_searchStart);
}
if (--m_count > 0)
{
Search(); // Kontynuacja zapytania.
}
else
{
m_gadu.Logout();
m_gadu.Disconnect();
}
}

private static void Main(string[] args)
{
Test test = new Test();
test.Search();
}
}

// --------------------------------------------------------------------------------------------------------

Za każdym razem (przy każdej kontynuacji) dostaję identyczne wyniki. Ponadto zwracane są kontakty z numerami gg niższymi niż zadany parametr FmStart (np. przy pierwszej kontynuacji parametr FmStart jest ustawiany na 10645484 a w wynikach jest kontakt o numerze 516284, tak jakby parametr FmStart w ogóle nie był uwzględniany. Wiem, że coś muszę robić nie tak jak trzeba, bo przecież w standardowym komunikatorze funkcja kontynuacji działa prawidłowo.

0

Chyba znalazłem rozwiązanie.
Parametr FmStart nie jest odpowiednikiem numeru gg!
Po wykonaniu zapytania do katalogu publicznego serwer zwraca serię wyników. Ostatni wiersz zawiera dane z zerowymi wartościami (numer gg = 0) oraz pewną liczbę w parametrze o nazwie "nextstart". Właśnie tę wartość trzeba pobrać z ostatniego wiersza wynikowego i przekazać ją do parametru FmStart w kolejnym zapytaniu.
Przy takim podejściu kontynuacja działa, ale też nie do końca tak jakby się można spodziewać. Otóż po (mniej więcej) 10 kontynuacjach ostatni wiersz wyniku zwraca "nextstart" = 0, więc dalsza kontynuacja jest niemożliwa. Tak jakby wyszukiwać można było tylko w jakimś początkowym zakresie numerów (mniej więcej do numeru gg 100000). Wygląda mi to na jakieś zabezpieczenie po stronie serwera gg - podobno robiono modyfikacje pod kątem bezpieczeństwa.

0

Witam.
A jak uruchomić program w sytuacji, gdy połączenie jest wykonane za pośrednictwem proxy ?

0

Klient SHGG ma o tyle wadę, że korzysta z metody RawSerialize, a do wielu stringów używa MarshalAs z właściwością ConstSize, której przypisuje się straszliwie wysoką wartość (1900+) bajtów.

Zatem każdy pakiet np. wiadomości do kogoś zajmuje wiecej niz 2kb, to czasami jest niedopuszczalne w szybkich transmisjach.

Pozdrawiam.

0

Jak kolega powyżej szukam rozwiązania jednak nigdzie go nie widać. Jak rozwiązać sprawę proxy? Obie biblioteki nie mają wsparcia - muszę podać IP,port,login i hasło aby dostać się do serwera.

Czy ktoś rozwiązał ten problem ?

0

To mój pierwszy post, więc witam wszystkich ;-)

Podjąłem się napisania własnego, prostego komunikatora na .NET. Chętnie wykorzystam jedną z Waszych bibliotek (skoro są open-source), jednak jak widzę zostały one wydane jakiś czas temu. Aby nie wynajdywać od nowa koła... czy ktoś ma może aktualniejszą wersję którejś z tych bibliotek? Od tamtego czasu na pewno nieco się w samym protokole gg zmieniło.
Oczywiście jeśli nikt tego nie ma to pozostanie mi aktualizacja na podstawie libgadu, ale może ktoś już jest nieco dalej?

0

podpowie ktoś jak używać tej biblioteki w VB.NET ?? bo po opisach z pliku pdf, nie mogę sobie poradzić, z użyciem biblioteki

1 użytkowników online, w tym zalogowanych: 0, gości: 1