public Server(ServerConfiguration config) { _sendBigDataDelay = config.SendBigDataDelay; _users = new UserMapCollection(); _queue = new ConcurrentQueue<IPEndPoint>(); _udpClient = new UdpClient(CreateBuilder(_queue), CreateServerState()); _sender = new BigDataSender(_udpClient, _users, _queue); _udpClient.Bind(IPAddress.Any, config.Port); }
static private void ExportCommentsMeta(Journal.OptionsRow or, ILJServer iLJ, SessionGenerateResponse sgr, ref int serverMaxID, int localMaxID, UserMapCollection umc, CommentCollection cc) { // this is a an unfortunately necessary step // we call export comments meta is to get the user map and to check if comment state has changed // it would be better to be able to provide a lastsync, but alas // see http://www.livejournal.com/developer/exporting.bml for more info int maxID = -1; while (maxID < serverMaxID) { Uri uri = new Uri(new Uri(or.ServerURL), string.Format(_exportcommentsmetapath, maxID + 1)); if (!or.IsUseJournalNull()) { uri = new Uri(uri.AbsoluteUri + string.Format("&authas={0}", or.UseJournal)); } HttpWebRequest w = HttpWebRequestFactory.Create(uri.AbsoluteUri, sgr.ljsession); using (Stream s = w.GetResponse().GetResponseStream()) { XmlTextReader xtr = new XmlTextReader(s); while (xtr.Read()) { if (xtr.NodeType == XmlNodeType.Element && xtr.Name == "usermap") { string id = xtr.GetAttribute("id"); string user = xtr.GetAttribute("user"); if (id != null && user != null && !umc.ContainsID(XmlConvert.ToInt32(id))) { umc.Add(new UserMap(XmlConvert.ToInt32(id), user)); } } else if (xtr.NodeType == XmlNodeType.Element && xtr.Name == "maxid") { xtr.Read(); serverMaxID = XmlConvert.ToInt32(xtr.Value); socb(new SyncOperationEventArgs(SyncOperation.ExportCommentsMeta, Math.Max(maxID, 0), serverMaxID)); } else if (xtr.NodeType == XmlNodeType.Element && xtr.Name == "comment") { string id = xtr.GetAttribute("id"); string posterid = xtr.GetAttribute("posterid"); string state = xtr.GetAttribute("state"); if (posterid == null) { posterid = "0"; } if (state == null) { state = "A"; } if (id != null) { cc.Add(new Comment(XmlConvert.ToInt32(id), XmlConvert.ToInt32(posterid), state, 0, 0, string.Empty, string.Empty, DateTime.MinValue)); } } else if (xtr.NodeType == XmlNodeType.Element && xtr.Name == "h2") { xtr.Read(); if (xtr.Value == "Error" && !or.IsUseJournalNull()) { throw new ExpectedSyncException(ExpectedError.CommunityAccessDenied, null); } } } xtr.Close(); } maxID = cc.GetMaxID(); } }
static private void Merge(Journal j, EventCollection ec, CommentCollection ccMeta, CommentCollection ccBody, UserMapCollection umc, SyncItemCollection deletedsic, LoginResponse lr, string communityPicURL, DateTime lastSync) { j.AcceptChanges(); // row states must be set to unchanged for loaddatarow to merge properly // update moods j.Moods.BeginLoadData(); foreach (Mood m in lr.moods) { j.Moods.LoadDataRow(new object[] { m.id, m.name, m.parent }, false); } j.Moods.EndLoadData(); // update userpics j.UserPics.Clear(); j.UserPics.BeginLoadData(); for (int i = 0; i < lr.pickws.Length; ++i) { j.UserPics.AddUserPicsRow(lr.pickws[i], lr.pickwurls[i]); } j.UserPics.EndLoadData(); // update users j.Users.BeginLoadData(); foreach (UserMap u in umc) { j.Users.LoadDataRow(new object[] { u.id, u.user }, false); } j.Users.LoadDataRow(new object[] { 0, "anonymous" }, false); j.Users.EndLoadData(); // update new/updated journal events j.Events.BeginLoadData(); foreach (Event e in ec) { j.Events.LoadDataRow(new object[] { e.itemid, DateTime.Parse(e.eventtime, CultureInfo.InvariantCulture), e.security, e.allowmask, e.subject, e.eventText, e.poster, e.anum, e.props.current_mood, e.props.current_moodid, e.props.current_music, e.props.opt_preformatted == 1, e.props.opt_nocomments == 1, e.props.picture_keyword, e.props.opt_backdated == 1, e.props.opt_noemail == 1, e.props.unknown8bit == 1, e.props.hasscreened == 1, e.props.revnum, e.props.commentalter, e.props.syn_link, e.props.syn_id, new DateTime(1970, 1, 1).AddSeconds(e.props.revtime), e.props.taglist }, false); } j.Events.EndLoadData(); // update comment meta (posterid and state can change) j.Comments.BeginLoadData(); foreach (Comment c in ccMeta) { Journal.CommentsRow cr = j.Comments.FindByID(c.id); if (cr != null) { cr.PosterID = c.posterid; cr.State = c.state; } } j.Comments.EndLoadData(); // update comment bodies j.Comments.BeginLoadData(); foreach (Comment c in ccBody) { j.Comments.LoadDataRow(new object[] { c.id, c.posterid, c.state, c.jitemid, c.parentid, c.body, c.subject, c.date }, false); } j.Comments.EndLoadData(); // update deleted journal events if (deletedsic != null) { foreach (SyncItem s in deletedsic) { Common.Journal.EventsRow er = j.Events.FindByID(int.Parse(s.item.Substring(_syncitemtypelogprefix.Length))); if (er != null) { j.Events.RemoveEventsRow(er); } } } // update options j.Options.DefaultPicURL = (lr.defaultpicurl != null && lr.defaultpicurl.Length > 0 ? lr.defaultpicurl : null); j.Options.CommunityPicURL = communityPicURL; j.Options.FullName = (lr.fullname != null && lr.fullname.Length > 0 ? lr.fullname : null); j.Options.LastSync = lastSync; }
static private void ThreadStart() { // The main threaded execution body for performing a sync. // This method is chopped up into smaller methods for clarity and structure. ILJServer iLJ; Journal.OptionsRow or = null; SyncItemCollection sic = null, deletedsic = null; EventCollection ec = null; CommentCollection ccbody = null, ccmeta = null; UserMapCollection umc = null; LoginResponse lr = new LoginResponse(); string communityPicURL = null; DateTime lastSync = DateTime.MinValue; SessionGenerateResponse sgr; int serverMaxID, localMaxID; try { // STEP 1: Initialize socb(new SyncOperationEventArgs(SyncOperation.Initialize, 0, 0)); syncException = null; or = j.Options; iLJ = LJServerFactory.Create(or.ServerURL); sic = new SyncItemCollection(); deletedsic = new SyncItemCollection(); ec = new EventCollection(); ccmeta = new CommentCollection(); ccbody = new CommentCollection(); umc = new UserMapCollection(); // STEP 2: Login socb(new SyncOperationEventArgs(SyncOperation.Login, 0, 0)); lr = new LoginResponse(); Login(or, iLJ, ref lr, ref communityPicURL); // STEP 3: SyncItems socb(new SyncOperationEventArgs(SyncOperation.SyncItems, 0, 0)); lastSync = DateTime.MinValue; SyncItems(or, iLJ, ref sic, ref deletedsic, ref lastSync); // STEP 4: GetEvents socb(new SyncOperationEventArgs(SyncOperation.GetEvents, 0, 0)); GetEvents(or, iLJ, ref sic, ref deletedsic, ref ec); if (or.GetComments) { // STEP 5: SessionGenerate socb(new SyncOperationEventArgs(SyncOperation.SessionGenerate, 0, 0)); sgr = new SessionGenerateResponse(); SessionGenerate(or, iLJ, ref sgr); // STEP 6: ExportCommentsMeta socb(new SyncOperationEventArgs(SyncOperation.ExportCommentsMeta, 0, 0)); localMaxID = serverMaxID = j.GetMaxCommentID(); ExportCommentsMeta(or, iLJ, sgr, ref serverMaxID, localMaxID, umc, ccmeta); // STEP 7: ExportCommentsBody socb(new SyncOperationEventArgs(SyncOperation.ExportCommentsBody, 0, 0)); ExportCommentsBody(or, iLJ, sgr, serverMaxID, localMaxID, ccbody); } } catch (Exception ex) { ParseException(ex, ref syncException); if (ex.GetType() == typeof(ThreadAbortException)) { socb(new SyncOperationEventArgs(SyncOperation.Failure, 0, 0)); // do this before thread terminates return; } } // STEP 8: Merge try { if (syncException == null) { socb(new SyncOperationEventArgs(SyncOperation.Merge, 0, 0)); Merge(j, ec, ccmeta, ccbody, umc, deletedsic, lr, communityPicURL, lastSync); socb(new SyncOperationEventArgs(SyncOperation.Success, ec.Count, ccbody.Count)); } else if (syncException.GetType() == typeof(ExpectedSyncException) && (((ExpectedSyncException)syncException).ExpectedError == ExpectedError.ServerNotResponding || ((ExpectedSyncException)syncException).ExpectedError == ExpectedError.ExportCommentsNotSupported || ((ExpectedSyncException)syncException).ExpectedError == ExpectedError.CommunityAccessDenied) && lr.moods != null) { socb(new SyncOperationEventArgs(SyncOperation.Merge, 0, 0)); if (sic.Count > 0) { lastSync = DateTime.Parse(sic.GetOldest().time, CultureInfo.InvariantCulture).AddSeconds(-1); } Merge(j, ec, ccmeta, ccbody, umc, deletedsic, lr, communityPicURL, lastSync); socb(new SyncOperationEventArgs(SyncOperation.PartialSync, ec.Count, ccbody.Count)); } else { socb(new SyncOperationEventArgs(SyncOperation.Failure, 0, 0)); } } catch (Exception ex) { syncException = ex; socb(new SyncOperationEventArgs(SyncOperation.Failure, 0, 0)); } }