/// <summary> /// Creates CAN IPNS record object to point to a CAN object of the given hash with the given sequence number. /// </summary> /// <param name="Hash">Hash of the CAN object to point IPNS record to.</param> /// <param name="SequenceNumber">Sequence number of the IPNS record.</param> public CanIpnsEntry CreateIpnsRecord(byte[] Hash, UInt64 SequenceNumber) { log.Trace("(Hash:'{0}',SequenceNumber:{1})", Hash.ToBase58(), SequenceNumber); string validityString = DateTime.UtcNow.AddMonths(1).ToString(Rfc3339DateTimeFormat, DateTimeFormatInfo.InvariantInfo); byte[] validityBytes = Encoding.UTF8.GetBytes(validityString); UInt64 ttlNanoSec = (UInt64)(TimeSpan.FromSeconds(IpnsRecordExpirationTimeSeconds).TotalMilliseconds) * (UInt64)1000000; string valueString = CanApi.CreateIpfsPathFromHash(Hash); byte[] valueBytes = Encoding.UTF8.GetBytes(valueString); CanIpnsEntry res = new CanIpnsEntry() { Sequence = SequenceNumber, ValidityType = CanIpnsEntry.Types.ValidityType.Eol, Ttl = ttlNanoSec, Validity = ProtocolHelper.ByteArrayToByteString(validityBytes), Value = ProtocolHelper.ByteArrayToByteString(valueBytes) }; res.Signature = ProtocolHelper.ByteArrayToByteString(CreateIpnsRecordSignature(res)); log.Trace("(-):{0}", res); return(res); }
public override bool Init() { log.Info("()"); bool res = false; try { canApi = (CanApi)Base.ComponentDictionary["Network.ContentAddressNetwork.CanApi"]; // Construct profile server's contact information CAN object. canContactInformation = new CanProfileServerContact() { PublicKey = ProtocolHelper.ByteArrayToByteString(Base.Configuration.Keys.PublicKey), IpAddress = ProtocolHelper.ByteArrayToByteString(Base.Configuration.ServerInterface.GetAddressBytes()), PrimaryPort = (uint)Base.Configuration.ServerRoles.GetRolePort(ServerRole.Primary) }; initThread = new Thread(new ThreadStart(InitThread)); initThread.Start(); res = true; Initialized = true; } catch (Exception e) { log.Error("Exception occurred: {0}", e.ToString()); } if (!res) { ShutdownSignaling.SignalShutdown(); if ((initThread != null) && !initThreadFinished.WaitOne(25000)) { log.Error("Init thread did not terminated in 25 seconds."); } } log.Info("(-):{0}", res); return(res); }
/// <summary> /// Refreshes profile server's IPNS record in CAN. /// </summary> /// <param name="IpnsRecord">IPNS record to refresh.</param> /// <param name="PublicKey">Public key of the IPNS record owner.</param> /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns> public async Task <CanRefreshIpnsResult> RefreshIpnsRecord(CanIpnsEntry IpnsRecord, byte[] PublicKey) { log.Trace("(PublicKey:'{0}')", PublicKey.ToHex()); string ipnsRecordEncoded = IpnsRecord.ToByteArray().ToBase64UrlPad(true); CanCryptoKey cryptoKey = new CanCryptoKey() { Type = CanCryptoKey.Types.KeyType.Ed25519, Data = ProtocolHelper.ByteArrayToByteString(PublicKey) }; string keyEncoded = Base58Encoding.Encoder.Encode(cryptoKey.ToByteArray()); log.Debug("Encoding public key: {0}", keyEncoded); NameValueCollection args = new NameValueCollection(); args.Add("arg", ipnsRecordEncoded); args.Add("key", keyEncoded); CanApiResult apiResult = await SendRequest("name/upload", args); CanRefreshIpnsResult res = CanRefreshIpnsResult.FromApiResult(apiResult); if (res.Success) { res.IsCanError = false; // Check that the ID, path and sequence number match what we expect. string canId = CanApi.PublicKeyToId(PublicKey).ToBase58(); if (res.Details.Peer == canId) { string path = Encoding.UTF8.GetString(IpnsRecord.Value.ToByteArray()); if (res.Details.NewPath == path) { if (res.Details.NewSeq == IpnsRecord.Sequence) { // All OK. } else { log.Warn("CAN sequence is {0}, received {1}.", IpnsRecord.Sequence, res.Details.NewSeq); res.Success = false; res.Message = "CAN path in response does not match expected value."; } } else { log.Warn("CAN path is '{0}', received '{1}'.", path, res.Details.NewPath); res.Success = false; res.Message = "CAN path in response does not match expected value."; } } else { log.Warn("CAN ID is '{0}', received '{1}'.", canId, res.Details.Peer); res.Success = false; res.Message = "CAN ID in response does not match expected value."; } } if (res.Success) { log.Trace("(-):*.Success={0}", res.Success); } else { log.Trace("(-):*.Success={0},*.IsCanError={1},*.Message='{2}'", res.Success, res.IsCanError, res.Message); } return(res); }
/// <summary> /// Thread that is initializes CAN objects during the profile server startup. /// </summary> private async void InitThread() { log.Info("()"); initThreadFinished.Reset(); if (Base.Configuration.CanProfileServerContactInformationHash != null) { log.Debug("Old CAN object hash is '{0}', object {1} change.", Base.Configuration.CanProfileServerContactInformationHash.ToBase58(), Base.Configuration.CanProfileServerContactInformationChanged ? "DID" : "did NOT"); } else { log.Debug("No CAN object found."); } bool deleteOldObject = Base.Configuration.CanProfileServerContactInformationChanged && (Base.Configuration.CanProfileServerContactInformationHash != null); byte[] canObject = canContactInformation.ToByteArray(); log.Trace("CAN object: {0}", canObject.ToHex()); while (!ShutdownSignaling.IsShutdown) { // First delete old CAN object if there is any. bool error = false; if (deleteOldObject) { string objectPath = CanApi.CreateIpfsPathFromHash(Base.Configuration.CanProfileServerContactInformationHash); CanDeleteResult cres = await canApi.CanDeleteObject(objectPath); if (cres.Success) { log.Info("Old CAN object hash '{0}' deleted.", Base.Configuration.CanProfileServerContactInformationHash.ToBase58()); } else { log.Warn("Failed to delete old CAN object hash '{0}', error message '{1}', will retry.", Base.Configuration.CanProfileServerContactInformationHash.ToBase58(), cres.Message); error = true; } } else { log.Trace("No old object to delete."); } if (ShutdownSignaling.IsShutdown) { break; } if (!error) { if (Base.Configuration.CanProfileServerContactInformationChanged) { // Now upload the new object. CanUploadResult cres = await canApi.CanUploadObject(canObject); if (cres.Success) { canContactInformationHash = cres.Hash; log.Info("New CAN object hash '{0}' added.", canContactInformationHash.ToBase58()); break; } log.Warn("Unable to add new object to CAN, error message: '{0}'", cres.Message); } else { canContactInformationHash = Base.Configuration.CanProfileServerContactInformationHash; log.Info("CAN object unchanged since last time, hash is '{0}'.", canContactInformationHash.ToBase58()); break; } } // Retry in 10 seconds. try { await Task.Delay(10000, ShutdownSignaling.ShutdownCancellationTokenSource.Token); } catch { // Catch cancellation exception. } } if (canContactInformationHash != null) { if (Base.Configuration.CanProfileServerContactInformationChanged) { // Save the new data to the database. if (!await SaveProfileServerContactInformation()) { log.Error("Failed to save new profile server contact information values to database."); } } // Finally, start IPNS record refreshing timer. await IpnsRecordRefresh(); } initThreadFinished.Set(); log.Info("(-)"); }