public synchronized void process() { WoTIdentityManager identityManager = (WoTIdentityManager) mFreetalk.getIdentityManager(); long now = CurrentTimeUTC.getInMillis(); try { MessageManager messageManager = mFreetalk.getMessageManager(); // We must tell the user to solve puzzles if he as written a message ... if (messageManager.getOwnMessagesBy(mOwner).size() > 0 || messageManager.getMessagesBy(mOwner).size() > 0) { // Also check for messages which are not stored as own messages anymore. int minimumTrusterCount = mFreetalk.getConfig().getInt(Config.MINIMUM_TRUSTER_COUNT); // ... and if he has not received enough trust values. if (identityManager.getReceivedTrustsCount(mOwner) < minimumTrusterCount) { mPuzzlesToSolve = minimumTrusterCount * 2; mNextDisplayTime = now; mNextProcessingTime = Long.MAX_VALUE; // Task is in display mode now, no need to proccess it anymore storeAndCommit(); return; } } mNextProcessingTime = now + PROCESSING_INTERVAL; storeAndCommit(); return; } catch (Exception e) { mNextProcessingTime = now + PROCESSING_INTERVAL_SHORT; Logger.error(this, "Error while processing an IntroduceIdentityTask", e); } }
public synchronized void onHideForSomeTime() { mPuzzlesToSolve = 0; mNextProcessingTime = CurrentTimeUTC.getInMillis() + PROCESSING_INTERVAL; mNextDisplayTime = Long.MAX_VALUE; storeAndCommit(); }
/** * Retrieves the session ID from the session cookie in the given {@link ToadletContext}, checks if * it contains a valid (existing and not expired) session and if yes, returns the {@link Session}. * * <p>If the session was valid, then its validity is extended by {@link MAX_SESSION_IDLE_TIME}. * * <p>If the session is not valid anymore, <code>null</code> is returned if the new constructor * was used (for example by PluginRespirator). If the deprecated constructor was used, a * RedirectException to the login URI is thrown. * * @throws RedirectException if login redirect URI was set */ public synchronized Session useSession(ToadletContext context) throws RedirectException { UUID sessionID = getSessionID(context); if (sessionID == null) { if (mLogInRedirectURI == null) return null; throw new RedirectException(mLogInRedirectURI); } // We must synchronize around the fetching of the time and mSessionsByID.push() because // mSessionsByID is no sorting data structure: It's a plain // LRUHashtable so to ensure that it stays sorted the operation "getTime(); push();" must be // atomic. long time = CurrentTimeUTC.getInMillis(); removeExpiredSessions(time); Session session = mSessionsByID.get(sessionID); if (session == null) { if (mLogInRedirectURI == null) return null; throw new RedirectException(mLogInRedirectURI); } session.updateExpiresAtTime(time); mSessionsByID.push(session.getID(), session); setSessionCookie(session, context); return session; }
protected PersistentTask(OwnIdentity myOwner) { mID = UUID.randomUUID().toString(); mOwner = myOwner; mNextProcessingTime = CurrentTimeUTC.getInMillis(); mNextDisplayTime = Long.MAX_VALUE; mDeleteTime = Long.MAX_VALUE; }
/** * Returns true if the given {@link ToadletContext} contains a session cookie for a valid * (existing and not expired) session. * * <p>In opposite to {@link getSessionUserID}, this function does NOT extend the validity of the * session. Therefore, this function can be considered as a way of peeking for a session, to * decide which Toadlet links should be visible. */ public synchronized boolean sessionExists(ToadletContext context) { UUID sessionID = getSessionID(context); if (sessionID == null) return false; removeExpiredSessions(CurrentTimeUTC.getInMillis()); return mSessionsByID.containsKey(sessionID); }
public synchronized void onPuzzleSolved() { if (mPuzzlesToSolve > 0) --mPuzzlesToSolve; if (mPuzzlesToSolve == 0) { mNextProcessingTime = CurrentTimeUTC.getInMillis() + PROCESSING_INTERVAL; mNextDisplayTime = Long.MAX_VALUE; } storeAndCommit(); }
/** * Fetches the identities with positive score from WoT and stores them in the database. * * @throws Exception */ private void fetchIdentities() throws Exception { // parseIdentities() acquires and frees the WoTIdentityManager-lock for each identity to allow // other threads to access the identity manager while the // parsing is in progress. Therefore, we do not take the lock for the whole execution of this // function. synchronized (this) { if (mIdentityFetchInProgress) return; long now = CurrentTimeUTC.getInMillis(); if ((now - mLastIdentityFetchTime) < MINIMAL_IDENTITY_FETCH_DELAY) return; mIdentityFetchInProgress = true; } try { Logger.normal(this, "Requesting identities with positive score from WoT ..."); SimpleFieldSet p1 = new SimpleFieldSet(true); p1.putOverwrite("Message", "GetIdentitiesByScore"); p1.putOverwrite("Selection", "+"); p1.putOverwrite("Context", Freetalk.WOT_CONTEXT); parseIdentities(sendFCPMessageBlocking(p1, null, "Identities").params, false); synchronized (this) { // We must update the fetch-time after the parsing and only if the parsing succeeded: // If we updated before the parsing and parsing failed or took ages (the thread sometimes // takes 2 hours to execute, don't ask me why) // then the garbage collector would delete identities. mLastIdentityFetchTime = CurrentTimeUTC.getInMillis(); } } finally { synchronized (this) { mIdentityFetchInProgress = false; } } // We usually call garbageCollectIdentities() after calling this function, it updates the cache // already... // if(mShortestUniqueNicknameCacheNeedsUpdate) // updateShortestUniqueNicknameCache(); }
/** * Creates a new session for the given user ID. * * <p>If a session for the given user ID already exists, it is deleted. It is not re-used to * ensure that parallel logins with the same user account from different computers do not work. * * @param context The ToadletContext in which the session cookie shall be stored. */ public synchronized Session createSession(String userID, ToadletContext context) { // We must synchronize around the fetching of the time and mSessionsByID.push() because // mSessionsByID is no sorting data structure: It's a plain // LRUHashtable so to ensure that it stays sorted the operation "getTime(); push();" must be // atomic. long time = CurrentTimeUTC.getInMillis(); removeExpiredSessions(time); deleteSessionByUserID(userID); Session session = new Session(userID, time); mSessionsByID.push(session.getID(), session); mSessionsByUserID.put(session.getUserID(), session); setSessionCookie(session, context); return session; }
// TODO: Remove ID parameter and compute the ID from the URI public WoTIdentity(String myID, FreenetURI myRequestURI, String myNickname) { if (myID == null) throw new IllegalArgumentException("ID == null"); if (myID.length() == 0) throw new IllegalArgumentException("ID.length() == 0"); if (myRequestURI == null) throw new IllegalArgumentException("RequestURI == null"); if (myNickname == null) throw new IllegalArgumentException("Nickname == null"); try { validateNickname(myNickname); } catch (InvalidParameterException e) { throw new IllegalArgumentException(e); } mID = myID; mRequestURI = myRequestURI; mNickname = myNickname; mLastReceivedFromWoT = CurrentTimeUTC.getInMillis(); IfNotEquals.thenThrow( IdentityID.construct(mID), IdentityID.constructFromURI(mRequestURI), "myID"); }
/** Debug function which checks whether the session LRU queue is in order; */ private synchronized void verifyQueueOrder() { long previousTime = 0; Enumeration<Session> sessions = mSessionsByID.values(); while (sessions.hasMoreElements()) { Session session = sessions.nextElement(); if (session.getExpirationTime() < previousTime) { long sessionAge = (CurrentTimeUTC.getInMillis() - session.getExpirationTime()) / (60 * 60 * 1000); Logger.error( this, "Session LRU queue out of order! Found session which is " + sessionAge + " hour old: " + session); Logger.error(this, "Deleting all sessions..."); mSessionsByID.clear(); mSessionsByUserID.clear(); return; } } }
@SuppressWarnings("unchecked") private void parseIdentities(SimpleFieldSet params, boolean bOwnIdentities) { if (bOwnIdentities) Logger.normal(this, "Parsing received own identities..."); else Logger.normal(this, "Parsing received identities..."); int idx; int ignoredCount = 0; int newCount = 0; for (idx = 0; ; idx++) { String identityID = params.get("Identity" + idx); if (identityID == null || identityID.equals("")) /* TODO: Figure out whether the second condition is necessary */ break; String requestURI = params.get("RequestURI" + idx); String insertURI = bOwnIdentities ? params.get("InsertURI" + idx) : null; String nickname = params.get("Nickname" + idx); if (nickname == null || nickname.length() == 0) { // If an identity publishes an invalid nickname in one of its first WoT inserts then WoT // will return an empty // nickname for that identity until a new XML was published with a valid nickname. We ignore // the identity until // then to prevent confusing error logs. // TODO: Maybe handle this in WoT. Would require checks in many places though. continue; } synchronized (this) { /* We lock here and not during the whole function to allow other threads to execute */ Query q = db.query(); // TODO: Encapsulate the query in a function... q.constrain(WoTIdentity.class); q.descend("mID").constrain(identityID); ObjectSet<WoTIdentity> result = q.execute(); WoTIdentity id = null; if (result.size() == 0) { try { importIdentity(bOwnIdentities, identityID, requestURI, insertURI, nickname); ++newCount; } catch (Exception e) { Logger.error(this, "Importing a new identity failed.", e); } } else { Logger.debug(this, "Not importing already existing identity " + requestURI); ++ignoredCount; assert (result.size() == 1); id = result.next(); id.initializeTransient(mFreetalk); if (bOwnIdentities != (id instanceof WoTOwnIdentity)) { // The type of the identity changed so we need to delete and re-import it. try { Logger.normal(this, "Identity type changed, replacing it: " + id); // We MUST NOT take the following locks because deleteIdentity does other locks // (MessageManager/TaskManager) which must happen before... // synchronized(id) // synchronized(db.lock()) deleteIdentity(id, mFreetalk.getMessageManager(), mFreetalk.getTaskManager()); importIdentity(bOwnIdentities, identityID, requestURI, insertURI, nickname); } catch (Exception e) { Logger.error(this, "Replacing a WoTIdentity with WoTOwnIdentity failed.", e); } } else { // Normal case: Update the last received time of the idefnt synchronized (id) { synchronized (db.lock()) { try { // TODO: The thread sometimes takes hours to parse the identities and I don't know // why. // So right now its better to re-query the time for each identity. id.setLastReceivedFromWoT(CurrentTimeUTC.getInMillis()); id.checkedCommit(this); } catch (Exception e) { Persistent.checkedRollback(db, this, e); } } } } } } Thread.yield(); } Logger.normal( this, "parseIdentities(bOwnIdentities==" + bOwnIdentities + " received " + idx + " identities. Ignored " + ignoredCount + "; New: " + newCount); }
/** Makes the list of Identities known by the tree owner. */ private void makeKnownIdentitiesList() { String nickFilter = mRequest.getPartAsStringFailsafe("nickfilter", 100).trim(); String sortBy = mRequest.isPartSet("sortby") ? mRequest.getPartAsStringFailsafe("sortby", 100).trim() : "Nickname"; String sortType = mRequest.isPartSet("sorttype") ? mRequest.getPartAsStringFailsafe("sorttype", 100).trim() : "Ascending"; int page = mRequest.isPartSet("page") ? Integer.parseInt( mRequest.getPartAsStringFailsafe( "page", Integer.toString(Integer.MAX_VALUE).length())) : 0; page = page - 1; // What we get passed is the user-friendly page number counting from 1, not 0. page = Math.max(0, page); // In case no page part was set, it would be -1 HTMLNode knownIdentitiesBox = addContentBox(l10n().getString("KnownIdentitiesPage.KnownIdentities.Header")); knownIdentitiesBox = pr.addFormChild(knownIdentitiesBox, uri.toString(), "Filters").addChild("p"); knownIdentitiesBox.addChild( "input", new String[] {"type", "name", "value"}, new String[] {"hidden", "page", Integer.toString(page + 1)}); InfoboxNode filtersBoxNode = getContentBox(l10n().getString("KnownIdentitiesPage.FiltersAndSorting.Header")); { // Filters box knownIdentitiesBox.addChild(filtersBoxNode.outer); HTMLNode filtersBox = filtersBoxNode.content; filtersBox.addChild( "#", l10n().getString("KnownIdentitiesPage.FiltersAndSorting.ShowOnlyNicksContaining") + " : "); filtersBox.addChild( "input", new String[] {"type", "size", "name", "value"}, new String[] {"text", "15", "nickfilter", nickFilter}); filtersBox.addChild( "#", " " + l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy") + " : "); HTMLNode option = filtersBox.addChild( "select", new String[] {"name", "id"}, new String[] {"sortby", "sortby"}); TreeMap<String, String> options = new TreeMap<String, String>(); options.put( SortBy.Edition.toString(), l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.Edition")); options.put( SortBy.Nickname.toString(), l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.Nickname")); options.put( SortBy.Score.toString(), l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.Score")); options.put( SortBy.LocalTrust.toString(), l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.LocalTrust")); for (String e : options.keySet()) { HTMLNode newOption = option.addChild("option", "value", e, options.get(e)); if (e.equals(sortBy)) { newOption.addAttribute("selected", "selected"); } } option = filtersBox.addChild( "select", new String[] {"name", "id"}, new String[] {"sorttype", "sorttype"}); options = new TreeMap<String, String>(); options.put( "Ascending", l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.Ascending")); options.put( "Descending", l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.Descending")); for (String e : options.keySet()) { HTMLNode newOption = option.addChild("option", "value", e, options.get(e)); if (e.equals(sortType)) { newOption.addAttribute("selected", "selected"); } } filtersBox.addChild( "input", new String[] {"type", "value"}, new String[] { "submit", l10n().getString("KnownIdentitiesPage.FiltersAndSorting.SortIdentitiesBy.SubmitButton") }); } // Display the list of known identities HTMLNode identitiesTable = knownIdentitiesBox.addChild("table", "border", "0"); identitiesTable.addChild(getKnownIdentitiesListTableHeader()); WebOfTrust.SortOrder sortInstruction = WebOfTrust.SortOrder.valueOf("By" + sortBy + sortType); synchronized (mWebOfTrust) { long currentTime = CurrentTimeUTC.getInMillis(); int indexOfFirstIdentity = page * IDENTITIES_PER_PAGE; // Re-query it instead of using mLoggedInOwnIdentity because mLoggedInOwnIdentity is a // clone() and thus will not work with database queries on the WebOfTrust. // TODO: Performance: This can be removed once the TODO at // WebPageImpl.getLoggedInOwnIdentityFromHTTPSession() of not cloning the // OwnIdentity has been been resolved. final OwnIdentity ownId; try { ownId = mWebOfTrust.getOwnIdentityByID(mLoggedInOwnIdentity.getID()); } catch (UnknownIdentityException e) { new ErrorPage(mToadlet, mRequest, mContext, e).addToPage(this); return; } ObjectSet<Identity> allIdentities = mWebOfTrust.getAllIdentitiesFilteredAndSorted(ownId, nickFilter, sortInstruction); Iterator<Identity> identities; try { identities = allIdentities.listIterator(indexOfFirstIdentity); } catch (IndexOutOfBoundsException e) { // The user supplied a higher page index than there are pages. This can happen when the // user changes the search filters while not being on the first page. // We fall back to displaying the last page. // Notice: We intentionally do not prevent listIterator() from throwing by checking // the index for validity before calling listIterator(). This is because we would need // to call allIdentities.size() to check the index. This would force the database to // compute the full result set even though we only need the results up to the current // page if we are not on the last page. page = getPageCount(allIdentities.size()) - 1; indexOfFirstIdentity = page * IDENTITIES_PER_PAGE; // TODO: Performance: Don't re-query this from the database once the issue which caused // this workaround is fixed: https://bugs.freenetproject.org/view.php?id=6646 allIdentities = mWebOfTrust.getAllIdentitiesFilteredAndSorted(ownId, nickFilter, sortInstruction); identities = allIdentities.listIterator(indexOfFirstIdentity); } for (int displayed = 0; displayed < IDENTITIES_PER_PAGE && identities.hasNext(); ++displayed) { final Identity id = identities.next(); if (id == ownId) continue; HTMLNode row = identitiesTable.addChild("tr"); // NickName HTMLNode nameLink = row.addChild( "td", new String[] {"title", "style"}, new String[] {id.getRequestURI().toString(), "cursor: help;"}) .addChild("a", "href", IdentityPage.getURI(mWebInterface, id.getID()).toString()); String nickName = id.getNickname(); if (nickName != null) { nameLink.addChild("#", nickName + "@" + id.getID().substring(0, 5) + "..."); } else nameLink .addChild("span", "class", "alert-error") .addChild( "#", l10n() .getString( "KnownIdentitiesPage.KnownIdentities.Table.NicknameNotDownloadedYet")); // Added date row.addChild( "td", CommonWebUtils.formatTimeDelta(currentTime - id.getAddedDate().getTime(), l10n())); // Last fetched date Date lastFetched = id.getLastFetchedDate(); if (!lastFetched.equals(new Date(0))) row.addChild( "td", CommonWebUtils.formatTimeDelta(currentTime - lastFetched.getTime(), l10n())); else row.addChild("td", l10n().getString("Common.Never")); // Publish TrustList row.addChild( "td", new String[] {"align"}, new String[] {"center"}, id.doesPublishTrustList() ? l10n().getString("Common.Yes") : l10n().getString("Common.No")); // Score try { final Score score = mWebOfTrust.getScore(ownId, id); final int scoreValue = score.getScore(); final int rank = score.getRank(); row.addChild( "td", new String[] {"align", "style"}, new String[] { "center", "background-color:" + KnownIdentitiesPage.getTrustColor(scoreValue) + ";" }, Integer.toString(scoreValue) + " (" + (rank != Integer.MAX_VALUE ? rank : l10n().getString("KnownIdentitiesPage.KnownIdentities.Table.InfiniteRank")) + ")"); } catch (NotInTrustTreeException e) { // This only happen with identities added manually by the user row.addChild("td", l10n().getString("KnownIdentitiesPage.KnownIdentities.Table.NoScore")); } // Own Trust row.addChild(getReceivedTrustCell(ownId, id)); // Checkbox row.addChild(getSetTrustCell(id)); // Nb Trusters // TODO: Do a direct link to the received-trusts part of the linked page HTMLNode trustersCell = row.addChild("td", new String[] {"align"}, new String[] {"center"}); trustersCell.addChild( new HTMLNode( "a", "href", IdentityPage.getURI(mWebInterface, id.getID()).toString(), Long.toString(mWebOfTrust.getReceivedTrusts(id).size()))); // Nb Trustees // TODO: Do a direct link to the given-trusts part of the linked page HTMLNode trusteesCell = row.addChild("td", new String[] {"align"}, new String[] {"center"}); trusteesCell.addChild( new HTMLNode( "a", "href", IdentityPage.getURI(mWebInterface, id.getID()).toString(), Long.toString(mWebOfTrust.getGivenTrusts(id).size()))); // TODO: Show in advanced mode only once someone finally fixes the "Switch to advanced mode" // link on FProxy to work on ALL pages. row.addChild("td", "align", "center", Long.toString(id.getEdition())); row.addChild("td", "align", "center", Long.toString(id.getLatestEditionHint())); } identitiesTable.addChild(getKnownIdentitiesListTableHeader()); knownIdentitiesBox.addChild(getKnownIdentitiesListPageLinks(page, allIdentities.size())); } }